# HG changeset patch # User Olaf Wintermann # Date 1598350076 -7200 # Node ID 0b8692959d3708dff17f648a2913dc37ca5cfd0c # Parent 5653a9626cc0053131139abef60dc60d7c0bde4a# Parent 134279e804b697d0440cfb046e2ab6acb8832a56 merge branch config into webdav diff -r 5653a9626cc0 -r 0b8692959d37 src/server/Makefile --- a/src/server/Makefile Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/Makefile Tue Aug 25 12:07:56 2020 +0200 @@ -62,7 +62,7 @@ OBJ_DIRS = daemon safs ucx util webdav config admin plugins test MK_OBJ_DIRS = $(OBJ_DIRS:%=$(OBJ_DIR)server/%) -CFLAGS += -I../ +CFLAGS += -I../ucx/ LDFLAGS += -lucx preparation: $(MK_OBJ_DIRS) diff -r 5653a9626cc0 -r 0b8692959d37 src/server/admin/admin.c --- a/src/server/admin/admin.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/admin/admin.c Tue Aug 25 12:07:56 2020 +0200 @@ -34,7 +34,6 @@ #include "../util/pblock.h" #include "../config/conf.h" -#include "../config/serverconf.h" #include "../config/objconf.h" static Page *root_page; diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/keyfile.c --- a/src/server/config/keyfile.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/config/keyfile.c Tue Aug 25 12:07:56 2020 +0200 @@ -31,7 +31,7 @@ #include "keyfile.h" -KeyfileConfig *load_keyfile_config(char *file) { +KeyfileConfig *load_keyfile_config(const char *file) { FILE *in = fopen(file, "r"); if(in == NULL) { return NULL; @@ -39,7 +39,7 @@ KeyfileConfig *conf = malloc(sizeof(KeyfileConfig)); conf->parser.parse = keyfile_parse; - conf->file = file; + conf->file = strdup(file); conf->users = NULL; int r = cfg_parse_basic_file((ConfigParser*)conf, in); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/keyfile.h --- a/src/server/config/keyfile.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/config/keyfile.h Tue Aug 25 12:07:56 2020 +0200 @@ -50,7 +50,7 @@ size_t numgroups; } KeyfileEntry; -KeyfileConfig *load_keyfile_config(char *file); +KeyfileConfig *load_keyfile_config(const char *file); void free_keyfile_config(KeyfileConfig *conf); int keyfile_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/mimeconf.c --- a/src/server/config/mimeconf.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/config/mimeconf.c Tue Aug 25 12:07:56 2020 +0200 @@ -38,7 +38,7 @@ void *ptr; } ucx_regdestr; -MimeConfig *load_mime_config(char *file) { +MimeConfig *load_mime_config(const char *file) { FILE *in = fopen(file, "r"); if(in == NULL) { return NULL; @@ -46,7 +46,6 @@ MimeConfig *conf = malloc(sizeof(MimeConfig)); conf->parser.parse = mimeconf_parse; - conf->file = file; conf->directives = NULL; conf->ntypes = 0; int r = cfg_parse_basic_file((ConfigParser*)conf, in); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/mimeconf.h --- a/src/server/config/mimeconf.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/config/mimeconf.h Tue Aug 25 12:07:56 2020 +0200 @@ -37,7 +37,6 @@ typedef struct _mime_conf { ConfigParser parser; - char *file; UcxList *directives; // MimeDirective list int ntypes; } MimeConfig; @@ -47,7 +46,7 @@ UcxList *exts; // char* } MimeDirective; -MimeConfig *load_mime_config(char *file); +MimeConfig *load_mime_config(const char *file); void free_mime_config(MimeConfig *conf); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/objs.mk --- a/src/server/config/objs.mk Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/config/objs.mk Tue Aug 25 12:07:56 2020 +0200 @@ -33,10 +33,10 @@ CONFOBJ = objconf.o CONFOBJ += conf.o CONFOBJ += initconf.o -CONFOBJ += serverconf.o CONFOBJ += mimeconf.o CONFOBJ += acl.o CONFOBJ += keyfile.o +CONFOBJ += serverconfig.o CONFOBJS = $(CONFOBJ:%=$(CONF_OBJPRE)%) CONFSOURCE = $(CONFOBJ:%.o=config/%.c) diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/serverconf.c --- a/src/server/config/serverconf.c Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2013 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#include "serverconf.h" - -ServerConfig *load_server_config(char *file) { - FILE *in = fopen(file, "r"); - if(in == NULL) { - return NULL; - } - - ServerConfig *conf = malloc(sizeof(ServerConfig)); - conf->parser.parse = serverconf_parse; - conf->file = file; - conf->obj = NULL; - - conf->objects = ucx_map_new(16); - int r = cfg_parse_basic_file((ConfigParser*)conf, in); - cfg_map_destr(conf->parser.mp->pool, conf->objects); - if(r != 0) { - // TODO: free - return NULL; - } - - fclose(in); - - return conf; -} - -void free_server_config(ServerConfig *conf) { - ucx_mempool_destroy(conf->parser.mp->pool); - free(conf); -} - -int serverconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line){ - ServerConfig *conf = p; - UcxAllocator *mp = conf->parser.mp; - - begin->type = cfg_get_line_type(line); - switch(begin->type) { - case LINE_BEGIN_TAG: { - ConfigTag *tag = cfg_parse_begin_tag(line, conf->parser.mp); - - // create server config object - ServerConfigObject *obj = OBJ_NEW( - conf->parser.mp, - ServerConfigObject); - obj->type = tag->name; - obj->begin = begin; - obj->end = end; - obj->directives = NULL; - - // add object to server config - UcxList *list = ucx_map_sstr_get(conf->objects, obj->type); - list = ucx_list_append_a(mp, list, obj); - ucx_map_sstr_put(conf->objects, obj->type, list); - conf->obj = obj; - - break; - } - case LINE_END_TAG: { - sstr_t tag = cfg_get_end_tag_name(line); - if(sstrcmp(tag, conf->obj->type) != 0) { - log_ereport(LOG_FAILURE, "server.conf: syntax error: wrong close tag"); - log_ereport(LOG_FAILURE, "open tag: %s close tag: %s", sstrdup(tag).ptr, sstrdup(conf->obj->type).ptr); - exit(-1); - } - conf->obj = NULL; - - break; - } - case LINE_DIRECTIVE: { - if(conf->obj == NULL) { - log_ereport(LOG_FAILURE, "server.conf: directive outside of object"); - exit(-1); - } - - ConfigDirective *d = cfg_parse_directive(line, conf->parser.mp); - d->begin = begin; - d->end = end; - - //printf("%s.%s\n", conf->obj->type.ptr, d->directive_type.ptr); - conf->obj->directives = ucx_list_append_a(mp, conf->obj->directives, d); - } - } - return 0; -} - - -UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxAllocator *mp, int *error) { - mp = mp ? mp : cfg->parser.mp; - - UcxList *list = ucx_map_sstr_get(cfg->objects, sstrn("Listener", 8)); - UcxList *lslist = NULL; - UCX_FOREACH(elm, list) { - ServerConfigObject *ls = elm->data; - sstr_t name = cfg_directivelist_get_str(ls->directives, sstr("Name")); - sstr_t port = cfg_directivelist_get_str(ls->directives, sstr("Port")); - sstr_t vs = cfg_directivelist_get_str( - ls->directives, - sstr("DefaultVS")); - sstr_t threadpool = cfg_directivelist_get_str( - ls->directives, - sstr("Threadpool")); - - CfgListener *listener = OBJ_NEW_N(mp, CfgListener); - // threadpool is optional, all other configs must be set - if(!name.ptr || !port.ptr || !vs.ptr) { - // TODO: log error - *error = 1; - listener->cfg_correct = 0; - } else { - listener->cfg_correct = 1; - } - - if(name.ptr) { - listener->name = sstrdup_a(mp, name); - } - if(port.ptr) { - // don't expect that port is null terminated, sstrdup it to be sure - sstr_t portdp = sstrdup(port); - listener->port = atoi(portdp.ptr); - free(portdp.ptr); - } - if(vs.ptr) { - listener->vs = sstrdup_a(mp, vs); - } - if(threadpool.ptr) { - listener->threadpool = sstrdup_a(mp, threadpool); - } - - lslist = ucx_list_append_a(mp, lslist, listener); - } - - return lslist; -} diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/serverconf.h --- a/src/server/config/serverconf.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2013 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SERVERCONF_H -#define SERVERCONF_H - -#include "conf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _server_conf_obj { - ConfigLine *begin; - ConfigLine *end; - - sstr_t type; - UcxList *directives; -} ServerConfigObject; - -typedef struct _server_conf { - ConfigParser parser; - char *file; - UcxMap *objects; // contains UcxList of ServerConfigObject - // parser temp vars - ServerConfigObject *obj; -} ServerConfig; - -// server.conf objects - -typedef struct _cfg_listener { - ServerConfigObject *cfgobj; - sstr_t name; - sstr_t vs; - sstr_t threadpool; - sstr_t address; - int port; - int nacceptors; - int cfg_correct; -} CfgListener; - -typedef struct _cfg_keyfile_authdb { - sstr_t file; -} CfgKeyfileAuthDB; - -typedef struct _cfg_ldap_authdb { - sstr_t host; - int port; - sstr_t basedn; - sstr_t binddn; - sstr_t bindpw; -} CfgLDAPAuthDB; - -union authdb { - CfgKeyfileAuthDB keyfile; - CfgLDAPAuthDB ldap; -}; - -enum authdb_type { - AUTHDB_TYPE_KEYFILE, - AUTHDB_TYPE_LDAP -}; - -typedef struct _cfg_authdb { - sstr_t name; - enum authdb_type type; - union authdb cfg; - int cfg_correct; -} CfgAuthDB; - - -/* - * Loads and parses a server configuration file. The function only structures - * the file content to configuration objects with directives. The semantics - * of the objects and directives can be extracted with the srvcfg_* funcsions. - */ -ServerConfig *load_server_config(char *file); - -/* - * frees the ServerConfig object - */ -void free_server_config(ServerConfig *conf); - -// private - parses a server.conf line -int serverconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line); - - -UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxAllocator *mp, int *error); - - -#ifdef __cplusplus -} -#endif - -#endif /* SERVERCONF_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/serverconfig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/config/serverconfig.c Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,323 @@ +/* + * 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 "serverconfig.h" + +#include +#include +#include +#include + +#include +#include + +ServerConfig* serverconfig_load(const char *file) { + FILE *in = fopen(file, "r"); + if(in == NULL) { + return NULL; + } + + UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); + if(!buf) { + fclose(in); + return NULL; + } + + ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); + fclose(in); + + ServerConfig *scfg = serverconfig_parse(scstrn(buf->space, buf->size)); + + ucx_buffer_free(buf); + return scfg; +} + + +static CFGToken get_next_token(scstr_t content, int *pos) { + CFGToken token = { {NULL, 0}, CFG_NO_TOKEN }; + CFGTokenType type = CFG_TOKEN; + + int start = *pos; + + int token_begin = -1; + int token_end = content.length-1; + + int quote = 0; + int comment = 0; + + int i; + char prev = 0; + for(i=start;i= 0) { + token_end = i; + break; + } + } else if(c == '"') { + quote = 1; + if(token_begin < 0) { + token_begin = i; + } + } else if(token_begin < 0) { + token_begin = i; + } + prev = c; + } + + *pos = i + 1; + + if(token_begin < 0) { + return token; // error + } + + token.type = type; + token.content = scstrsubsl(content, token_begin, token_end - token_begin); + return token; +} + +/* +static void test_print_config(ConfigNode *parent) { + UCX_FOREACH(elm, parent->children) { + ConfigNode *node = elm->data; + + if(node->type == CONFIG_NODE_SPACE) { + printf("sp: %s", node->text_begin.ptr); + } else if(node->type == CONFIG_NODE_COMMENT) { + printf("cm: %s", node->text_begin.ptr); + } else if(node->type == CONFIG_NODE_OBJECT) { + printf("o{: %s : %s", node->name.ptr, node->text_begin.ptr); + test_print_config(node); + printf("o}: %s", node->text_end.ptr); + } else if(node->type == CONFIG_NODE_DIRECTIVE) { + printf("di: %s", node->text_begin.ptr); + } else { + printf("fk: %s", node->text_begin.ptr); + } + } +} +*/ + +ServerConfig* serverconfig_parse(scstr_t content) { + UcxMempool *mp = ucx_mempool_new(512); + if(!mp) return NULL; + UcxAllocator *a = mp->allocator; + + ServerConfig *config = ucx_mempool_malloc(mp, sizeof(ServerConfig)); + if(!config) { + ucx_mempool_destroy(mp); + return NULL; + } + config->mp = mp; + + // PARSE: + // first non space/comment token is directive/object name + // following tokens are arguments + // newline starts new directive + // '{' converts directive to object and following directives will + // be placed into the object + int pos = 0; // needed for tokenizer + CFGToken token; + + ConfigNode *root_obj = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode)); + root_obj->type = CONFIG_NODE_OBJECT; + + UcxList *node_stack = ucx_list_prepend(NULL, root_obj); + + ConfigNode *current = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode)); + current->type = CONFIG_NODE_SPACE; + ConfigNode *obj = NULL; + int obj_closed = 0; + + int text_start = 0; + int err = 0; + while((token = get_next_token(content, &pos)).type != CFG_NO_TOKEN) { + //printf("%s [%.*s]\n", token_type_str(token.type), (int)token.content.length, token.content.ptr); + + switch(token.type) { + CFG_NO_TOKEN: break; + case CFG_TOKEN_COMMENT: { + if(current->type == CONFIG_NODE_SPACE) { + current->type = CONFIG_NODE_COMMENT; + } + break; + } + case CFG_TOKEN_SPACE: break; + case CFG_TOKEN_NEWLINE: { + scstr_t line = scstrsubsl(content, text_start, pos - text_start); + text_start = pos; + + sstr_t line_cp = sstrdup_a(a, line); + + ConfigNode *parent = node_stack->data; + if(current->type == CONFIG_NODE_CLOSE_OBJECT) { + parent->text_end = line_cp; + node_stack = ucx_list_remove_a(a, node_stack, node_stack); + } else if(current->type == CONFIG_NODE_OPEN_OBJECT) { + sstr_t new_textbegin = sstrcat_a(a, 2, obj->text_begin, line_cp); + alfree(a, obj->text_begin.ptr); + alfree(a, line_cp.ptr); + obj->text_begin = new_textbegin; + } else { + current->text_begin = line_cp; + ConfigNode *parent = node_stack->data; + parent->children = ucx_list_append_a(a, parent->children, current); + } + + if(obj && obj->type == CONFIG_NODE_OBJECT) { + node_stack = ucx_list_prepend_a(a, node_stack, obj); + obj = NULL; + } + + current = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode)); + current->type = CONFIG_NODE_SPACE; + + obj_closed = 0; + break; + } + case CFG_TOKEN: { + if(!sstrcmp(token.content, S("{"))) { + if(!obj) { + err = 1; + break; + } + obj->type = CONFIG_NODE_OBJECT; + if(current != obj) { + current->type = CONFIG_NODE_OPEN_OBJECT; + } + } else if(!sstrcmp(token.content, S("}"))) { + obj_closed = 1; // force newline before next directive + obj = NULL; + current->type = CONFIG_NODE_CLOSE_OBJECT; + } else { + if(obj_closed) { + err = 1; + break; + } + + if(!current->name.ptr) { + current->name = sstrdup_a(a, token.content); + current->type = CONFIG_NODE_DIRECTIVE; + obj = current; + } else { + ConfigArg *arg = ucx_mempool_calloc(mp, 1, sizeof(ConfigArg)); + // TODO: add support for key/value + arg->value = sstrdup_a(a, token.content); + current->args = ucx_list_append_a(a, current->args, arg); + } + } + break; + } + } + + if(err) { + break; + } + } + + if(pos < content.length || err) { + // content not fully parsed because of an error + ucx_mempool_destroy(mp); + return NULL; + } + + //test_print_config(&root_obj); + config->root = root_obj; + config->tab = sstrdup_a(a, SC("\t")); + + return config; +} + +void serverconfig_free(ServerConfig *cfg) { + ucx_mempool_destroy(cfg->mp); +} + +ConfigNode* serverconfig_get_node(ConfigNode *parent, ConfigNodeType type, scstr_t name) { + UCX_FOREACH(elm, parent->children) { + ConfigNode *node = elm->data; + if(node->type == type && !sstrcmp(node->name, name)) { + return node; + } + } + return NULL; +} + +UcxList* serverconfig_get_node_list(ConfigNode *parent, ConfigNodeType type, scstr_t name) { + UcxList *nodes = NULL; + + UCX_FOREACH(elm, parent->children) { + ConfigNode *node = elm->data; + if(node->type == type && !sstrcmp(node->name, name)) { + nodes = ucx_list_append(nodes, node); + } + } + + return nodes; +} + +scstr_t serverconfig_directive_value(ConfigNode *obj, scstr_t name) { + ConfigNode *node = serverconfig_get_node(obj, CONFIG_NODE_DIRECTIVE, name); + if(node && ucx_list_size(node->args) == 1) { + ConfigArg *arg = node->args->data; + return SCSTR(arg->value); + } + return scstrn(NULL, 0); +} diff -r 5653a9626cc0 -r 0b8692959d37 src/server/config/serverconfig.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/config/serverconfig.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,110 @@ +/* + * 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_CONFIG_SERVERCONFIG_H +#define WS_CONFIG_SERVERCONFIG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct ServerConfig ServerConfig; +typedef struct ConfigNode ConfigNode; +typedef struct ConfigArg ConfigArg; +typedef struct CFGToken CFGToken; + +typedef enum ConfigNodeType ConfigNodeType; +typedef enum CFGTokenType CFGTokenType; + +struct ServerConfig { + UcxMempool *mp; + ConfigNode *root; + sstr_t tab; +}; + +enum ConfigNodeType { + CONFIG_NODE_SPACE = 0, + CONFIG_NODE_COMMENT, + CONFIG_NODE_OBJECT, + CONFIG_NODE_DIRECTIVE, + CONFIG_NODE_OPEN_OBJECT, + CONFIG_NODE_CLOSE_OBJECT +}; + +struct ConfigNode { + sstr_t text_begin; + sstr_t text_end; + ConfigNodeType type; + + sstr_t name; + UcxList *args; + UcxList *children; +}; + +struct ConfigArg { + sstr_t name; + sstr_t value; +}; + + +enum CFGTokenType { + CFG_NO_TOKEN = 0, + CFG_TOKEN_COMMENT, + CFG_TOKEN_SPACE, + CFG_TOKEN_NEWLINE, + CFG_TOKEN +}; + +struct CFGToken { + scstr_t content; + CFGTokenType type; +}; + +ServerConfig* serverconfig_load(const char *file); + +ServerConfig* serverconfig_parse(scstr_t content); + +void serverconfig_free(ServerConfig *cfg); + +ConfigNode* serverconfig_get_node(ConfigNode *parent, ConfigNodeType type, scstr_t name); + +UcxList* serverconfig_get_node_list(ConfigNode *parent, ConfigNodeType type, scstr_t name); + +scstr_t serverconfig_directive_value(ConfigNode *obj, scstr_t name); + +#ifdef __cplusplus +} +#endif + +#endif /* WS_CONFIG_SERVERCONFIG_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/acldata.c --- a/src/server/daemon/acldata.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/acldata.c Tue Aug 25 12:07:56 2020 +0200 @@ -32,39 +32,20 @@ #include "acldata.h" -ACLData* acl_data_new() { - ACLData *dat = malloc(sizeof(ACLData)); - dat->ref = 1; +ACLData* acl_data_new(UcxAllocator *a) { + ACLData *dat = almalloc(a, sizeof(ACLData)); + if(!dat) { + return NULL; + } - dat->namedACLs = ucx_map_new(16); + dat->namedACLs = ucx_map_new_a(a, 16); + if(!dat->namedACLs) { + return NULL; + } return dat; } -void acl_data_ref(ACLData *acldata) { - if(acldata) { - ws_atomic_inc32(&acldata->ref); - } -} - -void acl_data_unref(ACLData *acldata) { - uint32_t ref = ws_atomic_dec32(&acldata->ref); - if(ref == 0) { - UcxMapIterator i = ucx_map_iterator(acldata->namedACLs); - WSAcl *acl; - UCX_MAP_FOREACH(key, acl, i) { - free(acl->ace); - free(acl->ece); - if(acl->acl.authprompt) { - free(acl->acl.authprompt); - } - free(acl); - } - ucx_map_free(acldata->namedACLs); - free(acldata); - } -} - ACLList* acl_get(ACLData *acldata, char *name) { ACLList *acl = ucx_map_cstr_get(acldata->namedACLs, name); return acl; diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/acldata.h --- a/src/server/daemon/acldata.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/acldata.h Tue Aug 25 12:07:56 2020 +0200 @@ -41,12 +41,9 @@ typedef struct acl_data { UcxMap *namedACLs; - uint32_t ref; } ACLData; ACLData* acl_data_new(); -void acl_data_ref(ACLData *acldata); -void acl_data_unref(ACLData *acldata); ACLList* acl_get(ACLData *acldata, char *name); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/auth.h --- a/src/server/daemon/auth.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/auth.h Tue Aug 25 12:07:56 2020 +0200 @@ -33,6 +33,8 @@ #include #include "../public/auth.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -48,12 +50,12 @@ typedef struct user_cache_elm UserCacheElm; struct user_cache_elm { - CachedUser *user; - UserCacheElm *next_user; // next elm in the cached user list - UcxKey key; // key to access this element - size_t slot; // slot in the map - UserCacheElm *next_elm; // next element in this map slot - time_t created; + CachedUser *user; + UserCacheElm *next_user; // next elm in the cached user list + UcxKey key; // key to access this element + size_t slot; // slot in the map + UserCacheElm *next_elm; // next element in this map slot + time_t created; }; typedef struct { diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/config.c --- a/src/server/daemon/config.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/config.c Tue Aug 25 12:07:56 2020 +0200 @@ -55,10 +55,8 @@ #include "../util/atomic.h" #include "ucx/buffer.h" -pool_handle_t *cfg_pool; +pool_handle_t *init_pool; -// TODO: Funktion für ConfigDirective -> directive -// TODO: Funktion für UcxList parameter list -> pblock int load_init_conf(char *file) { log_ereport(LOG_VERBOSE, "load_init_conf"); @@ -70,14 +68,14 @@ } UcxAllocator *mp = cfg->parser.mp; - cfg_pool = pool_create(); // one pool for one Configuration + init_pool = pool_create(); // one pool for one Configuration UcxList *dirs = cfg->directives; while(dirs != NULL) { ConfigDirective *dir = dirs->data; /* create NSAPI directive */ directive *d = malloc(sizeof(directive)); - d->param = pblock_create_pool(cfg_pool, 8); + d->param = pblock_create_pool(init_pool, 8); UcxList *param = cfg_param_list(dir->value, mp); while(param != NULL) { ConfigParam *p = param->data; @@ -127,19 +125,29 @@ return 0; } -ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file) { +ServerConfiguration* load_server_conf(char *file) { log_ereport(LOG_VERBOSE, "load_server_conf"); - ServerConfig *serverconf = load_server_config(file); - if(serverconf == NULL) { + ServerConfig *serverconf = serverconfig_load(file); + if(!serverconf) { log_ereport(LOG_FAILURE, "Cannot load server.conf"); + return NULL; } - ServerConfiguration *serverconfig = calloc(1, sizeof(ServerConfiguration)); + + pool_handle_t *pool = pool_create(); + + + ServerConfiguration *serverconfig = pool_calloc(pool, 1, sizeof(ServerConfiguration)); serverconfig->ref = 1; - serverconfig->pool = pool_create(); + 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; + // TODO: init serverconfig stuff @@ -161,49 +169,54 @@ */ // init logfile first - UcxList *lfl = ucx_map_sstr_get(serverconf->objects, sstrn("LogFile", 7)); - if(lfl != NULL) { - ServerConfigObject *logobj = lfl->data; - if(logobj == NULL) { + UcxList *list = NULL; + + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("LogFile")); + if(list) { + ConfigNode *logobj = list->data; + if(!logobj) { // error - return NULL; + return NULL; // TODO: fix memory leak } int ret = cfg_handle_logfile(serverconfig, logobj); if(ret != 0) { // cannot initialize log file - return NULL; + return NULL; // TODO: fix memory leak } } else { // horrible error return NULL; } + ucx_list_free(list); - UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Runtime")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; - if(cfg_handle_runtime(serverconfig, scfgobj)) { + ConfigNode *runtimeobj = elm->data; + if(cfg_handle_runtime(serverconfig, runtimeobj)) { // error return NULL; } } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("Threadpool", 10)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Threadpool")); UCX_FOREACH(elm, list) { if(cfg_handle_threadpool(serverconfig, elm->data)) { return NULL; } } + ucx_list_free(list); // check thread pool config if(check_thread_pool_cfg() != 0) { /* critical error */ return NULL; } - list = ucx_map_sstr_get(serverconf->objects, sstrn("EventHandler", 12)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("EventHandler")); UCX_FOREACH(elm, list) { if(cfg_handle_eventhandler( - serverconfig, (ServerConfigObject*)elm->data)) { + serverconfig, elm->data)) { // error return NULL; } @@ -213,38 +226,43 @@ /* critical error */ return NULL; } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AccessLog")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; + ConfigNode *scfgobj = elm->data; if(cfg_handle_accesslog(serverconfig, scfgobj)) { return NULL; } } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AuthDB")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; + ConfigNode *scfgobj = elm->data; if(cfg_handle_authdb(serverconfig, scfgobj)) { return NULL; } } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("Listener", 8)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Listener")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; + ConfigNode *scfgobj = elm->data; if(cfg_handle_listener(serverconfig, scfgobj)) { return NULL; } } + ucx_list_free(list); - list = ucx_map_sstr_get(serverconf->objects, sstrn("VirtualServer", 13)); + list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("VirtualServer")); UCX_FOREACH(elm, list) { - ServerConfigObject *scfgobj = elm->data; + ConfigNode *scfgobj = elm->data; if(cfg_handle_vs(serverconfig, scfgobj)) { return NULL; } } + ucx_list_free(list); // set VirtualServer for all listeners @@ -268,7 +286,8 @@ ls = ls->next; } - free_server_config(serverconf); + serverconfig_free(serverconf); + return serverconfig; } @@ -279,8 +298,7 @@ void cfg_unref(ServerConfiguration *cfg) { uint32_t ref = ws_atomic_dec32(&cfg->ref); if(ref == 0) { - // TODO: free configuration - printf("free ServerConfiguration %"PRIxPTR"\n", (intptr_t)cfg); + pool_destroy(cfg->pool); } } @@ -289,53 +307,36 @@ } -int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) { - sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User")); +int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t user = serverconfig_directive_value(obj, SC("User")); if(user.ptr) { - cfg->user = sstrdup_pool(cfg->pool, user); + cfg->user = sstrdup_a(cfg->a, user); } - sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp")); + scstr_t tmp = serverconfig_directive_value(obj, SC("Temp")); if(tmp.ptr) { - cfg->tmp = sstrdup_pool(cfg->pool, tmp); + cfg->tmp = sstrdup_a(cfg->a, tmp); } else { + // TODO: do this check after all config loading is done log_ereport(LOG_MISCONFIG, "no temporary directory specified"); return -1; } // mime file - sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile")); - sstr_t base = sstr("config/"); + scstr_t mf = serverconfig_directive_value(obj, SC("MimeFile")); + scstr_t base = SC("config/"); sstr_t file = sstrcat(2, base, mf); - ConfigFile *f = cfgmgr_get_file(file); - if(f == NULL) { - f = malloc(sizeof(ConfigFile)); - f->data = NULL; - f->file = sstrdup(file); - f->reload = mime_conf_reload; - f->last_modified = 0; - - // load the file content - //f->reload(f, cfg); - if(cfgmgr_reload_file(f, cfg, NULL)) { - free(f->file.ptr); - free(f); - - free(file.ptr); - return -1; - } - cfgmgr_attach_file(f); + if(mime_conf_load(cfg, file)) { + return -1; } - cfg->mimetypes = f->data; - free(file.ptr); return 0; } -int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj) { - sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File")); - sstr_t lvl = cfg_directivelist_get_str(obj->directives, sstr("Level")); +int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t file = serverconfig_directive_value(obj, SC("File")); + scstr_t lvl = serverconfig_directive_value(obj, SC("Level")); if(file.ptr == NULL || lvl.ptr == NULL) { /* missing log file parameters */ @@ -343,21 +344,18 @@ } LogConfig logcfg; - logcfg.file = sstrdup(file).ptr; - logcfg.level = sstrdup(lvl).ptr; + logcfg.file = file.ptr; + logcfg.level = lvl.ptr; logcfg.log_stdout = 0; logcfg.log_stderr = 0; /* TODO: stdout, stderr config */ int ret = init_log_file(&logcfg); - - free(logcfg.file); - free(logcfg.level); return ret; } -int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj) { ThreadPoolConfig poolcfg; poolcfg.min_threads = 4; poolcfg.min_threads = 4; @@ -365,21 +363,11 @@ poolcfg.queue_size = 64; poolcfg.stack_size = 262144; - sstr_t name = cfg_directivelist_get_str( - obj->directives, - sstr("Name")); - sstr_t min = cfg_directivelist_get_str( - obj->directives, - sstr("MinThreads")); - sstr_t max = cfg_directivelist_get_str( - obj->directives, - sstr("MaxThreads")); - sstr_t stack = cfg_directivelist_get_str( - obj->directives, - sstr("StackSize")); - sstr_t queue = cfg_directivelist_get_str( - obj->directives, - sstr("QueueSize")); + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t min = serverconfig_directive_value(obj, SC("MinThreads")); + scstr_t max = serverconfig_directive_value(obj, SC("MaxThreads")); + scstr_t stack = serverconfig_directive_value(obj, SC("StackSize")); + scstr_t queue = serverconfig_directive_value(obj, SC("QueueSize")); // TODO: Type if(name.length == 0) { @@ -388,27 +376,19 @@ } if(min.length != 0) { - min = sstrdup(min); poolcfg.min_threads = atoi(min.ptr); - free(min.ptr); } if(max.length != 0) { - max = sstrdup(max); poolcfg.max_threads = atoi(max.ptr); - free(max.ptr); } if(stack.length != 0) { - stack = sstrdup(stack); poolcfg.stack_size = atoi(stack.ptr); - free(stack.ptr); } if(queue.length != 0) { - queue = sstrdup(queue); poolcfg.queue_size = atoi(queue.ptr); - free(queue.ptr); } create_threadpool(name, &poolcfg); @@ -416,32 +396,26 @@ return 0; } -int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *obj) { +int cfg_handle_eventhandler(ServerConfiguration *c, ConfigNode *obj) { EventHandlerConfig evcfg; - sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name")); - sstr_t threads = cfg_directivelist_get_str( - obj->directives, - sstr("Threads")); - sstr_t isdefault = cfg_directivelist_get_str( - obj->directives, - sstr("Default")); + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t threads = serverconfig_directive_value(obj, SC("Threads")); + scstr_t isdefault = serverconfig_directive_value(obj, SC("Default")); evcfg.name = name; - sstr_t s = sstrdup(threads); - evcfg.nthreads = atoi(s.ptr); - free(s.ptr); + evcfg.nthreads = atoi(threads.ptr); evcfg.isdefault = util_getboolean(isdefault.ptr, 0); return create_event_handler(&evcfg); } -int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj) { // TODO: use a name to identify the log file - sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File")); + scstr_t file = serverconfig_directive_value(obj, SC("File")); if(file.ptr == NULL) { return 0; } @@ -456,10 +430,10 @@ return 0; } AccessLog *log = pool_malloc(cfg->pool, sizeof(AccessLog)); - log->file = sstrdup_pool(cfg->pool, file); + log->file = sstrdup_a(cfg->a, file); log->format = format; log->log = log_file; - cfg->logfiles = ucx_list_append(cfg->logfiles, log); + cfg->logfiles = ucx_list_append_a(cfg->a, cfg->logfiles, log); if(!cfg->default_log) { cfg->default_log = log; @@ -468,61 +442,31 @@ return 0; } -int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) { - sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name")); - sstr_t type = cfg_directivelist_get_str(obj->directives, sstr("Type")); +int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj) { + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t type = serverconfig_directive_value(obj, SC("Type")); + + AuthDB *authdb = NULL; if(!sstrcmp(type, sstr("ldap"))) { LDAPConfig conf; - sstr_t host = cfg_directivelist_get_str( - obj->directives, - sstr("Host")); - sstr_t port = cfg_directivelist_get_str( - obj->directives, - sstr("Port")); - sstr_t basedn = cfg_directivelist_get_str( - obj->directives, - sstr("BaseDN")); - sstr_t binddn = cfg_directivelist_get_str( - obj->directives, - sstr("BindDN")); - sstr_t basepw = cfg_directivelist_get_str( - obj->directives, - sstr("BindPW")); - - host = sstrdup(host); - port = sstrdup(port); - basedn = sstrdup(basedn); - binddn = sstrdup(binddn); - basepw = sstrdup(basepw); + scstr_t host = serverconfig_directive_value(obj, SC("Host")); + scstr_t port = serverconfig_directive_value( obj, SC("Port")); + scstr_t basedn = serverconfig_directive_value(obj, SC("BaseDN")); + scstr_t binddn = serverconfig_directive_value(obj, SC("BindDN")); + scstr_t basepw = serverconfig_directive_value(obj, SC("BindPW")); - conf.hostname = host.ptr; + conf.hostname = sstrdup_a(cfg->a, host).ptr; conf.port = atoi(port.ptr); - conf.basedn = basedn.ptr; - conf.binddn = binddn.ptr; - conf.bindpw = basepw.ptr; - - name = sstrdup(name); - - AuthDB *authdb = create_ldap_authdb(name.ptr, &conf); - ucx_map_sstr_put(cfg->authdbs, name, authdb); + conf.basedn = sstrdup_a(cfg->a, basedn).ptr; + conf.binddn = sstrdup_a(cfg->a, binddn).ptr; + conf.bindpw = sstrdup_a(cfg->a, basepw).ptr; - // TODO: create_ldap_authdb should copy the strings - /* - free(host.ptr); - free(port.ptr); - free(basedn.ptr); - free(binddn.ptr); - free(basepw.ptr); - free(name.ptr); - */ - + authdb = create_ldap_authdb(cfg, name.ptr, &conf); } else if(!sstrcmp(type, sstr("keyfile"))) { // we only need the file parameter - sstr_t file = cfg_directivelist_get_str( - obj->directives, - sstr("File")); + scstr_t file = serverconfig_directive_value(obj, SC("File")); if(file.length == 0) { log_ereport( LOG_MISCONFIG, @@ -531,67 +475,45 @@ } // load keyfile - ConfigFile *f = cfgmgr_get_file(file); - if(f == NULL) { - f = malloc(sizeof(ConfigFile)); - f->data = NULL; - f->file = sstrdup(file); - f->reload = keyfile_reload; - f->last_modified = 0; - //f->reload(f, cfg); - if(cfgmgr_reload_file(f, cfg, NULL)) { - free(f->file.ptr); - free(f); - return -1; - } - cfgmgr_attach_file(f); - } - - // add keyfile authdb - Keyfile *keyfile = f->data; - keyfile->authdb.name = sstrdup(name).ptr; - ucx_map_sstr_put(cfg->authdbs, name, keyfile); + authdb = keyfile_load(cfg, file); } + if(authdb) { + if(ucx_map_sstr_put(cfg->authdbs, name, authdb)) { + return -1; + } + } + return 0; } -int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj) { ListenerConfig lc; ZERO(&lc, sizeof(ListenerConfig)); lc.cfg = cfg; lc.port = 8080; lc.nacceptors = 1; - // TODO: use sstrdup_pool? - lc.name = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Name"))); - lc.port = atoi(cfg_directivelist_get_str( - obj->directives, - sstr("Port")).ptr); - lc.vs = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("DefaultVS"))); - lc.threadpool = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Threadpool"))); + scstr_t name = serverconfig_directive_value(obj, SC("Name")); + scstr_t port = serverconfig_directive_value(obj, SC("Port")); + scstr_t vs = serverconfig_directive_value(obj, SC("DefaultVS")); + scstr_t thrp = serverconfig_directive_value(obj, SC("Threadpool")); + scstr_t blck = serverconfig_directive_value(obj, SC("BlockingIO")); - sstr_t blockingio = cfg_directivelist_get_str( - obj->directives, - sstr("BlockingIO")); - if(blockingio.ptr) { - lc.blockingio = util_getboolean_s(blockingio, WS_FALSE); - } + // TODO: use sstrdup_pool? + lc.name = sstrdup(name); + lc.port = atoi(port.ptr); + lc.vs = sstrdup(vs); + lc.threadpool = sstrdup(thrp); - sstr_t ssl = cfg_directivelist_get_str(obj->directives, S("SSL")); + lc.blockingio = util_getboolean_s(blck, WS_FALSE); + + scstr_t ssl = serverconfig_directive_value(obj, SC("SSL")); if(util_getboolean_s(ssl, WS_FALSE)) { - sstr_t cert = cfg_directivelist_get_str(obj->directives, S("Cert")); - sstr_t privkey = cfg_directivelist_get_str(obj->directives, S("Key")); - sstr_t chain = cfg_directivelist_get_str(obj->directives, S("CertChain")); - sstr_t disableprot = cfg_directivelist_get_str( - obj->directives, - S("SSLDisableProtocol")); + scstr_t cert = serverconfig_directive_value(obj, SC("Cert")); + scstr_t privkey = serverconfig_directive_value(obj, SC("Key")); + scstr_t chain = serverconfig_directive_value(obj, SC("CertChain")); + scstr_t disableprot = serverconfig_directive_value(obj, SC("SSLDisableProtocol")); WSBool config_ok = WS_TRUE; // TODO: log error @@ -628,84 +550,50 @@ return 1; } - listener->default_vs.vs_name = lc.vs.ptr; - cfg->listeners = ucx_list_append(cfg->listeners, listener); + listener->default_vs.vs_name = sstrdup_a(cfg->a, lc.vs).ptr; + cfg->listeners = ucx_list_append_a(cfg->a, cfg->listeners, listener); return 0; } -int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) { +int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj) { VirtualServer *vs = vs_new(); - vs->name = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Name"))); - vs->host = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("Host"))); - vs->document_root = sstrdup(cfg_directivelist_get_str( - obj->directives, - sstr("DocRoot"))); - sstr_t objfile = cfg_directivelist_get_str( - obj->directives, - sstr("ObjectFile")); - sstr_t aclfile = cfg_directivelist_get_str( - obj->directives, - sstr("ACLFile")); + vs->name = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Name"))); + vs->host = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Host"))); + vs->document_root = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("DocRoot"))); + + scstr_t objfile = serverconfig_directive_value(obj, SC("ObjectFile")); + scstr_t aclfile = serverconfig_directive_value(obj, SC("ACLFile")); // load the object config file sstr_t base = sstr("config/"); sstr_t file = sstrcat(2, base, objfile); - file = sstrcat(2, base, objfile); + // sstrcat with allocator because we want to keep the string + file = sstrcat_a(cfg->a, 2, base, objfile); - // the file is managed by the configuration manager - ConfigFile *f = cfgmgr_get_file(file); - if(f == NULL) { - f = malloc(sizeof(ConfigFile)); - f->data = NULL; - f->file = sstrdup(file); - f->reload = object_conf_reload; - f->last_modified = 0; - //f->reload(f, cfg); - if(cfgmgr_reload_file(f, cfg, NULL)) { - free(f->file.ptr); - free(f); - - free(file.ptr); - return -1; - } - cfgmgr_attach_file(f); + HTTPObjectConfig *httpobj = objconf_load(cfg, file); + if(!httpobj) { + return -1; } - vs->objectfile = sstrdup(file); - vs->objects = (HTTPObjectConfig*)f->data; - free(file.ptr); + vs->objectfile = file; + vs->objects = httpobj; // load acl config file file = sstrcat(2, base, aclfile); - ConfigFile *aclf = cfgmgr_get_file(file); - if(aclf == NULL) { - aclf = malloc(sizeof(ConfigFile)); - aclf->data = NULL; - aclf->file = sstrdup(file); - aclf->reload = acl_conf_reload; - aclf->last_modified = 0; - //aclf->reload(aclf, cfg); - if(cfgmgr_reload_file(aclf, cfg, NULL)) { - free(aclf->file.ptr); - free(aclf); - - free(file.ptr); - return -1; - } - cfgmgr_attach_file(aclf); + ACLData *acldata = acl_conf_load(cfg, file); + if(!acldata) { + return -1; } - vs->acls = aclf->data; + vs->acls = acldata; + free(file.ptr); + // set the access log for the virtual server - // TODO: don't use always the default + // TODO: don't always use the default vs->log = cfg->default_log; ucx_map_sstr_put(cfg->host_vs, vs->host, vs); @@ -714,53 +602,8 @@ } -int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { - HTTPObjectConfig *old_conf = file->data; - file->data = load_obj_conf(file->file.ptr); - if(old_conf) { - object_conf_unref(old_conf); - } - if(file->data) { - return 0; - } else { - return 1; - } -} - -void object_conf_ref(HTTPObjectConfig *conf) { - if(conf) { - ws_atomic_inc32(&conf->ref); - } -} - -void object_conf_unref(HTTPObjectConfig *conf) { - uint32_t ref = ws_atomic_dec32(&conf->ref); - if(ref == 0) { - printf("free HTTPObjectConfig %"PRIxPTR"\n", (intptr_t)conf); - pool_destroy(conf->pool); - } -} - -HTTPObjectConfig* load_obj_conf(char *file) { - log_ereport(LOG_VERBOSE, "load_obj_conf"); - - // new conf function test - ObjectConfig *cfg = load_object_config(file); - UcxAllocator *mp = cfg->parser.mp; - if(cfg == NULL) { - return NULL; - } - - // create object config - pool_handle_t *pool = pool_create(); - HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1); - conf->pool = pool; - - // convert ObjectConfig to HTTPObjectConfig - - // add objects - conf->nobj = ucx_list_size(cfg->objects); - conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*)); +static int convert_objconf(ServerConfiguration *scfg, ObjectConfig *cfg, HTTPObjectConfig *conf, sstr_t file) { + pool_handle_t *pool = conf->pool; UcxList *objlist = cfg->objects; int i = 0; @@ -772,13 +615,16 @@ char *ppath = NULL; if(cob->name.length > 0) { name = sstrdup_pool(pool, cob->name).ptr; + if(!name) return -1; } if(cob->ppath.length > 0) { ppath = sstrdup_pool(pool, cob->ppath).ptr; + if(!ppath) return -1; } // create and add object httpd_object *obj = object_new(pool, name); + if(!obj) return -1; obj->path = NULL; conf->objects[i] = obj; @@ -788,8 +634,9 @@ UcxList *dirs = cob->directives[j]; while(dirs != NULL) { ConfigDirective *cfgdir = dirs->data; - + directive *d = pool_malloc(pool, sizeof(directive)); + if(!d) return -1; if(cfgdir->condition) { sstr_t expr = cfgdir->condition->param_str; d->cond = condition_from_str(pool, expr.ptr, expr.length); @@ -799,7 +646,7 @@ d->param = pblock_create_pool(pool, 8); // add params - UcxList *param = cfg_param_list(cfgdir->value, mp); + UcxList *param = cfg_param_list(cfgdir->value, scfg->a); while(param != NULL) { ConfigParam *p = param->data; pblock_nvlinsert( @@ -814,13 +661,13 @@ // get function char *func_name = pblock_findval("fn", d->param); if(!func_name) { - log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file); - return NULL; + log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file.ptr); + return -1; } d->func = get_function(func_name); if(!d->func) { log_ereport(LOG_MISCONFIG, "func %s not found", func_name); - return NULL; + return -1; } dirs = dirs->next; @@ -834,66 +681,94 @@ i++; objlist = objlist->next; } + + return 0; +} + +HTTPObjectConfig* objconf_load(ServerConfiguration *scfg, sstr_t file) { + log_ereport(LOG_VERBOSE, "load_obj_conf"); + + int ret = 0; + + // create object config + pool_handle_t *pool = scfg->pool; + HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1); + if(!conf) { + return NULL; + } + conf->pool = pool; + + // load obj config file + ObjectConfig *cfg = load_object_config(file.ptr); + if(!cfg) { + return NULL; + } + + // convert ObjectConfig to HTTPObjectConfig + + // add objects + conf->nobj = ucx_list_size(cfg->objects); + conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*)); + if(conf->objects) { + ret = convert_objconf(scfg, cfg, conf, file); + } else { + ret = -1; + } free_object_config(cfg); - return conf; + return !ret ? conf : NULL; } -int mime_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { - MimeConfig *mimecfg = load_mime_config(file->file.ptr); - MimeMap *old_conf = file->data; - - MimeMap *mimemap = malloc(sizeof(MimeMap)); - mimemap->ref = 1; - UcxMap *map = ucx_map_new((mimecfg->ntypes * 3) / 2); - mimemap->map = map; - - // add ext type pairs - UCX_FOREACH(md, mimecfg->directives) { - MimeDirective *d = md->data; - // add the type for each extension to the map - UCX_FOREACH(xl, d->exts) { - sstr_t ext = sstr(xl->data); - sstr_t value = sstrdup(d->type); - ucx_map_sstr_put(map, ext, value.ptr); - } +int mime_conf_load(ServerConfiguration *cfg, sstr_t file) { + MimeConfig *mimecfg = load_mime_config(file.ptr); + if(!mimecfg) { + return -1; } - file->data = mimemap; + int ret = 0; + + // cleanup in case of errors is done by the allocator + MimeMap *mimemap = almalloc(cfg->a, sizeof(MimeMap)); + UcxMap *map = ucx_map_new_a(cfg->a, (mimecfg->ntypes * 3) / 2); - if(old_conf) { - mime_conf_unref(old_conf); + if(mimemap && map) { + mimemap->map = map; + + // add ext type pairs + UCX_FOREACH(md, mimecfg->directives) { + MimeDirective *d = md->data; + // add the type for each extension to the map + UCX_FOREACH(xl, d->exts) { + sstr_t ext = sstr(xl->data); + sstr_t value = sstrdup(d->type); + if(ucx_map_sstr_put(map, ext, value.ptr)) { + ret = -1; + break; + } + } + if(ret) { + break; + } + } + + cfg->mimetypes = mimemap; + } else { + ret = -1; } free_mime_config(mimecfg); - return 0; -} - -void mime_conf_ref(MimeMap *conf) { - if(conf) { - ws_atomic_inc32(&conf->ref); - } + return ret; } -void mime_conf_unref(MimeMap *conf) { - uint32_t ref = ws_atomic_dec32(&conf->ref); - if(ref == 0) { - printf("free MimeConfig %"PRIxPTR"\n", (intptr_t)conf); - UcxMapIterator i = ucx_map_iterator(conf->map); - char *str; - UCX_MAP_FOREACH(key, str, i) { - free(str); - } - ucx_map_free(conf->map); - free(conf); - } -} + -int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg) { - ACLFile *aclfile = load_acl_file(file->file.ptr); +ACLData* acl_conf_load(ServerConfiguration *cfg, sstr_t file) { + ACLFile *aclfile = load_acl_file(file.ptr); - ACLData *acldata = acl_data_new(); + // TODO: malloc return checks + + ACLData *acldata = acl_data_new(cfg->a); UCX_FOREACH(elm, aclfile->namedACLs) { ACLConfig *ac = elm->data; ACLList *acl = acl_config_convert(cfg, ac); @@ -902,17 +777,13 @@ } free_acl_file(aclfile); - ACLData *old_data = file->data; - file->data = acldata; - if(old_data) { - acl_data_unref(old_data); - } - - return 0; + return acldata; } ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl) { - WSAcl *acllist = malloc(sizeof(WSAcl)); + UcxAllocator *a = cfg->a; + + WSAcl *acllist = almalloc(cfg->a, sizeof(WSAcl)); acllist->acl.check = (acl_check_f)wsacl_check; acllist->acl.authdb = NULL; acllist->acl.authprompt = NULL; @@ -925,8 +796,8 @@ } size_t s = ucx_list_size(acl->entries); - WSAce **aces = calloc(s, sizeof(WSAce*)); - WSAce **eces = calloc(s, sizeof(WSAce*)); + WSAce **tmp_aces = calloc(s, sizeof(WSAce*)); + WSAce **tmp_eces = calloc(s, sizeof(WSAce*)); int ai = 0; int ei = 0; @@ -935,36 +806,36 @@ ACEConfig *acecfg = elm->data; // copy data - WSAce *ace = malloc(sizeof(WSAce)); + WSAce *ace = almalloc(a, sizeof(WSAce)); ace->access_mask = acecfg->access_mask; ace->flags = acecfg->flags; ace->type = acecfg->type; - ace->who = sstrdup(acecfg->who).ptr; + ace->who = sstrdup_a(a, acecfg->who).ptr; // add the entry to the correct array if(ace->type >= ACL_TYPE_AUDIT) { - eces[ei] = ace; + tmp_eces[ei] = ace; ei++; } else { - aces[ai] = ace; + tmp_aces[ai] = ace; ai++; } } // create new entrie arrays with perfect fitting size if(ai > 0) { - acllist->ace = calloc(ai, sizeof(WSAce*)); + acllist->ace = alcalloc(a, ai, sizeof(WSAce*)); } if(ei > 0) { - acllist->ece = calloc(ei, sizeof(WSAce*)); + acllist->ece = alcalloc(a, ei, sizeof(WSAce*)); } - memcpy(acllist->ace, aces, ai*sizeof(WSAce*)); - memcpy(acllist->ece, eces, ei*sizeof(WSAce*)); + memcpy(acllist->ace, tmp_aces, ai*sizeof(WSAce*)); + memcpy(acllist->ece, tmp_eces, ei*sizeof(WSAce*)); acllist->acenum = ai; acllist->ecenum = ei; - free(aces); - free(eces); + free(tmp_aces); + free(tmp_eces); // get authentication information if(acl->authparam) { @@ -975,7 +846,7 @@ AuthDB *authdb = ucx_map_sstr_get(cfg->authdbs, authdb_str); acllist->acl.authdb = authdb; if(authdb && prompt_str.ptr) { - acllist->acl.authprompt = sstrdup(prompt_str).ptr; + acllist->acl.authprompt = sstrdup_a(a, prompt_str).ptr; } } } @@ -983,69 +854,35 @@ return &acllist->acl; } -int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg) { - KeyfileConfig *conf = load_keyfile_config(file->file.ptr); - if(!conf) { - return 1; +AuthDB* keyfile_load(ServerConfiguration *cfg, scstr_t file) { + Keyfile *keyfile = keyfile_new(cfg->a); + if(!keyfile) { + return NULL; } - Keyfile *keyfile = keyfile_new(); + KeyfileConfig *conf = load_keyfile_config(file.ptr); + if(!conf) { + return NULL; + } + + AuthDB *ret = &keyfile->authdb; UCX_FOREACH(elm, conf->users) { KeyfileEntry *user = elm->data; - keyfile_add_user( + if(keyfile_add_user( keyfile, user->name, user->hashtype, user->hashdata, user->groups, - user->numgroups); + user->numgroups)) + { + ret = NULL; + break; + } } free_keyfile_config(conf); - Keyfile *old_data = file->data; - file->data = keyfile; - if(old_data) { - keyfile_unref(old_data); - } - - return 0; + return ret; } - - -sstr_t cfg_load_file(sstr_t file) { - sstr_t r; - r.ptr = NULL; - r.length = 0; - - if(!file.ptr) { - return r; - } - - sstr_t f = sstrdup(file); - FILE *in = fopen(f.ptr, "r"); - if(!in) { - return r; - } - - UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - if(!buf) { - fclose(in); - return r; - } - - if(ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write) == 0) { - fclose(in); - ucx_buffer_free(buf); - return r; - } - - r.ptr = buf->space; - r.length = buf->pos; - - free(buf); - fclose(in); - - return r; -} diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/config.h --- a/src/server/daemon/config.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/config.h Tue Aug 25 12:07:56 2020 +0200 @@ -35,10 +35,10 @@ #include "../config/objconf.h" #include "../config/initconf.h" -#include "../config/serverconf.h" #include "../config/mimeconf.h" #include "../config/acl.h" #include "../config/keyfile.h" +#include "../config/serverconfig.h" #include "acldata.h" #include "keyfile_auth.h" @@ -57,6 +57,8 @@ typedef struct _server_configuration { pool_handle_t *pool; + UcxAllocator *a; + UcxMap *host_vs; // map of all vservers. key is the host name UcxList *listeners; // list of all listeners UcxList *logfiles; @@ -69,59 +71,42 @@ } ServerConfiguration; -typedef struct ConfigFile ConfigFile; - -typedef int(*cfg_reload_f)(ConfigFile*,ServerConfiguration*); - -struct ConfigFile { - sstr_t file; - time_t last_modified; - cfg_reload_f reload; - void *data; -}; - struct mime_map { UcxMap *map; - uint32_t ref; }; int load_init_conf(char *file); void init_server_config_parser(); -int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_eventhandler(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_eventhandler(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj); -int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj); +int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj); -ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file); +ServerConfiguration* load_server_conf(char *file); void cfg_ref(ServerConfiguration *cfg); void cfg_unref(ServerConfiguration *cfg); +HTTPObjectConfig* objconf_load(ServerConfiguration *scfg, sstr_t file); +int mime_conf_load(ServerConfiguration *cfg, sstr_t file); -int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg); -void object_conf_ref(HTTPObjectConfig *conf); -void object_conf_unref(HTTPObjectConfig *conf); -HTTPObjectConfig* load_obj_conf(char *file); -int mime_conf_reload(ConfigFile *file, ServerConfiguration *cfg); -void mime_conf_ref(MimeMap *conf); -void mime_conf_unref(MimeMap *conf); -int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg); +ACLData* acl_conf_load(ServerConfiguration *cfg, sstr_t file); ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl); -int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg); +AuthDB* keyfile_load(ServerConfiguration *cfg, scstr_t file); -sstr_t cfg_load_file(sstr_t file); + #ifdef __cplusplus } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/configmanager.c --- a/src/server/daemon/configmanager.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/configmanager.c Tue Aug 25 12:07:56 2020 +0200 @@ -38,111 +38,39 @@ #include "configmanager.h" static ServerConfiguration *current_config = NULL; -static time_t sc_last_modified = 0; -static UcxMap *config_files; static conf_global_vars_s global_vars; void init_configuration_manager() { /* init parser */ init_server_config_parser(); - - config_files = ucx_map_new(16); } NSAPI_PUBLIC conf_global_vars_s* conf_getglobals() { return &global_vars; } -void cfgmgr_attach_file(ConfigFile *cf) { - ucx_map_sstr_put(config_files, cf->file, cf); -} - -ConfigFile* cfgmgr_get_file(sstr_t name) { - return ucx_map_sstr_get(config_files, name); -} - -int cfgmgr_reload_file(ConfigFile *f, ServerConfiguration *conf, int *reload) { - struct stat s; - if(stat(f->file.ptr, &s) != 0) { - fprintf( - stderr, - "Error: Cannot get stat of file %s\n", f->file.ptr); - perror("cfgmgr_load_config: stat"); - return -1; - } +int cfgmgr_load_config(ServerConfiguration **set_cfg) { + ServerConfiguration *config = load_server_conf("config/server.conf"); - //printf("1 time: %d - %d\n", f->last_modified, s.st_mtim.tv_sec); - if(f->last_modified != s.st_mtime) { - /* reload the file */ - if(f->last_modified != 0) { - log_ereport( - LOG_INFORM, - "reload configuration file: %s", - f->file.ptr); - } - if(f->reload(f, conf)) { - return -1; - } - f->last_modified = s.st_mtime; - if(reload) { - *reload = 1; - } - } - return 0; -} - -int cfgmgr_load_config(ServerConfiguration **set_cfg) { - int cfgreload = 0; - - /* check config files */ - UcxMapIterator iter = ucx_map_iterator(config_files); - ConfigFile *f; - UCX_MAP_FOREACH(key, f, iter) { - if(cfgmgr_reload_file(f, current_config, &cfgreload) == -1) { - return -1; - } - } - - struct stat s; - if(stat("config/server.conf", &s) != 0) { - perror("stat(\"config/server.conf\")"); + if(!config) { return -1; } - - ServerConfiguration *config; - if(cfgreload || !current_config || sc_last_modified != s.st_mtime) { - config = load_server_conf( - current_config, - "config/server.conf"); - - if(config == NULL) { - return -1; - } - - sc_last_modified = s.st_mtime; - } else { - log_ereport(LOG_VERBOSE, "no reconfig required"); - config = current_config; - } if(set_cfg) { *set_cfg = config; } - ServerConfiguration *old_conf = NULL; - if(current_config != config) { - old_conf = current_config; + + if(current_config) { + cfg_unref(current_config); } current_config = config; - if(old_conf) { - cfg_unref(old_conf); - } + return 0; } ServerConfiguration *cfgmgr_get_server_config() { - //cfg_ref(current_config); return current_config; } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/configmanager.h --- a/src/server/daemon/configmanager.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/configmanager.h Tue Aug 25 12:07:56 2020 +0200 @@ -46,9 +46,6 @@ void init_configuration_manager(); -void cfgmgr_attach_file(ConfigFile *cf); -ConfigFile* cfgmgr_get_file(sstr_t name); -int cfgmgr_reload_file(ConfigFile *f, ServerConfiguration *conf, int *reload); int cfgmgr_load_config(ServerConfiguration **cfg); ServerConfiguration* cfgmgr_get_server_config(); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/event.c --- a/src/server/daemon/event.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/event.c Tue Aug 25 12:07:56 2020 +0200 @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "../../ucx/map.h" +#include #include "../util/atomic.h" #include "event.h" @@ -88,7 +88,7 @@ } EventHandlerConfig cfg; - cfg.name = sstr("default"); + cfg.name = SC("default"); cfg.nthreads = 1; cfg.isdefault = 1; diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/event.h --- a/src/server/daemon/event.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/event.h Tue Aug 25 12:07:56 2020 +0200 @@ -43,7 +43,7 @@ } EVHandler; typedef struct event_handler_conf { - sstr_t name; + scstr_t name; int nthreads; int isdefault; } EventHandlerConfig; diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/httplistener.c --- a/src/server/daemon/httplistener.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/httplistener.c Tue Aug 25 12:07:56 2020 +0200 @@ -237,23 +237,18 @@ } // TODO: cleanup on error - sstr_t file; int ret; char errbuf[512]; if(!conf->chainfile.ptr) { - file = sstrdup(conf->certfile); - ret = SSL_CTX_use_certificate_file(ctx, file.ptr, SSL_FILETYPE_PEM); - free(file.ptr); + ret = SSL_CTX_use_certificate_file(ctx, conf->certfile.ptr, SSL_FILETYPE_PEM); if(!ret) { ERR_error_string(ERR_get_error(), errbuf); log_ereport(LOG_MISCONFIG, "Cannot load ssl chain file: %s", errbuf); return NULL; } } else { - file = sstrdup(conf->chainfile); - ret = SSL_CTX_use_certificate_chain_file(ctx, file.ptr); - free(file.ptr); + ret = SSL_CTX_use_certificate_chain_file(ctx, conf->chainfile.ptr); if(!ret) { ERR_error_string(ERR_get_error(), errbuf); log_ereport(LOG_MISCONFIG, "Cannot load ssl cert file: %s", errbuf); @@ -261,9 +256,7 @@ } } - file = sstrdup(conf->privkeyfile); - ret = SSL_CTX_use_PrivateKey_file(ctx, file.ptr, SSL_FILETYPE_PEM); - free(file.ptr); + ret = SSL_CTX_use_PrivateKey_file(ctx, conf->privkeyfile.ptr, SSL_FILETYPE_PEM); if(!ret) { ERR_error_string(ERR_get_error(), errbuf); log_ereport(LOG_MISCONFIG, "Cannot load ssl key file: %s", errbuf); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/httplistener.h --- a/src/server/daemon/httplistener.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/httplistener.h Tue Aug 25 12:07:56 2020 +0200 @@ -64,10 +64,10 @@ int nacceptors; WSBool blockingio; WSBool ssl; - sstr_t certfile; - sstr_t privkeyfile; - sstr_t chainfile; - sstr_t disable_proto; + scstr_t certfile; + scstr_t privkeyfile; + scstr_t chainfile; + scstr_t disable_proto; }; struct _acceptor { diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/keyfile_auth.c --- a/src/server/daemon/keyfile_auth.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/keyfile_auth.c Tue Aug 25 12:07:56 2020 +0200 @@ -43,40 +43,18 @@ #include "keyfile_auth.h" -Keyfile* keyfile_new() { - Keyfile *keyfile = malloc(sizeof(Keyfile)); +Keyfile* keyfile_new(UcxAllocator *a) { + Keyfile *keyfile = alcalloc(a, 1, sizeof(Keyfile)); + if(!keyfile) { + return NULL; + } keyfile->authdb.get_user = keyfile_get_user; keyfile->authdb.use_cache = 0; - keyfile->users = ucx_map_new(16); - keyfile->ref = 1; + keyfile->users = ucx_map_new_a(a, 16); return keyfile; } -void keyfile_ref(Keyfile *keyfile) { - ws_atomic_inc32(&keyfile->ref); -} - -void keyfile_unref(Keyfile *keyfile) { - uint32_t ref = ws_atomic_dec32(&keyfile->ref); - if(ref == 0) { - UcxMapIterator i = ucx_map_iterator(keyfile->users); - KeyfileUser *user; - UCX_MAP_FOREACH(key, user, i) { - free(user->user.name); - free(user->hash); - for(int n=0;nnumgroups;n++) { - free(user->groups[n].ptr); - } - free(user->groups); - } - ucx_map_free(keyfile->users); - - free(keyfile->authdb.name); - free(keyfile); - } -} - -void keyfile_add_user( +int keyfile_add_user( Keyfile *keyfile, sstr_t name, enum KeyfileHashType hash_type, @@ -84,14 +62,16 @@ sstr_t *groups, size_t ngroups) { + UcxAllocator *a = keyfile->users->allocator; + if(hash.length < 12) { // hash too short // TODO: log - return; + return -1; } - KeyfileUser *user = malloc(sizeof(KeyfileUser)); - user->user.name = sstrdup(name).ptr; + KeyfileUser *user = almalloc(a, sizeof(KeyfileUser)); + user->user.name = sstrdup_a(a, name).ptr; user->user.uid = -1; user->user.gid = -1; user->user.verify_password = keyfile_user_verify_password; @@ -99,16 +79,29 @@ user->user.free = keyfile_user_free; user->hash_type = hash_type; - user->hash = malloc(hash.length + 1); + user->hash = almalloc(a, hash.length + 1); + + if(!user->user.name || !user->hash) { + return -1; + } + user->hashlen = util_base64decode(hash.ptr, hash.length, user->hash); - user->groups = calloc(ngroups, sizeof(sstr_t)); - for(int i=0;igroups[i] = sstrdup(groups[i]); + if(ngroups > 0) { + user->groups = alcalloc(a, ngroups, sizeof(sstr_t)); + if(!user->groups) { + return -1; + } + for(int i=0;igroups[i] = sstrdup(groups[i]); + } + + } else { + user->groups = NULL; } // add to keyfile - ucx_map_sstr_put(keyfile->users, name, user); + return ucx_map_sstr_put(keyfile->users, name, user); } // authdb functions diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/keyfile_auth.h --- a/src/server/daemon/keyfile_auth.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/keyfile_auth.h Tue Aug 25 12:07:56 2020 +0200 @@ -48,9 +48,8 @@ }; struct keyfile { - AuthDB authdb; - UcxMap *users; - uint32_t ref; + AuthDB authdb; + UcxMap *users; }; struct keyfile_user { @@ -62,11 +61,9 @@ size_t hashlen; }; -Keyfile* keyfile_new(); -void keyfile_ref(Keyfile *keyfile); -void keyfile_unref(Keyfile *keyfile); +Keyfile* keyfile_new(UcxAllocator *a); -void keyfile_add_user( +int keyfile_add_user( Keyfile *keyfile, sstr_t user, enum KeyfileHashType hash_type, diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/ldap_auth.c --- a/src/server/daemon/ldap_auth.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/ldap_auth.c Tue Aug 25 12:07:56 2020 +0200 @@ -47,9 +47,9 @@ #endif } -AuthDB* create_ldap_authdb(char *name, LDAPConfig *conf) { - LDAPAuthDB *authdb = malloc(sizeof(LDAPAuthDB)); - authdb->authdb.name = strdup(name); +AuthDB* create_ldap_authdb(ServerConfiguration *cfg, const char *name, LDAPConfig *conf) { + LDAPAuthDB *authdb = almalloc(cfg->a, sizeof(LDAPAuthDB)); + authdb->authdb.name = pool_strdup(cfg->pool, name); authdb->authdb.get_user = ldap_get_user; authdb->authdb.use_cache = 1; authdb->config = *conf; @@ -64,7 +64,7 @@ // initialize group cache authdb->groups.first = NULL; authdb->groups.last = NULL; - authdb->groups.map = ucx_map_new(32); + authdb->groups.map = ucx_map_new_a(cfg->a, 32); return (AuthDB*) authdb; } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/ldap_auth.h --- a/src/server/daemon/ldap_auth.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/ldap_auth.h Tue Aug 25 12:07:56 2020 +0200 @@ -34,6 +34,8 @@ #include #include +#include "config.h" + #ifdef __cplusplus extern "C" { #endif @@ -90,7 +92,7 @@ LDAPGroup *next; }; -AuthDB* create_ldap_authdb(char *name, LDAPConfig *conf); +AuthDB* create_ldap_authdb(ServerConfiguration *cfg, const char *name, LDAPConfig *conf); LDAP* get_ldap_session(LDAPAuthDB *authdb); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/log.c --- a/src/server/daemon/log.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/log.c Tue Aug 25 12:07:56 2020 +0200 @@ -335,7 +335,9 @@ * This source file only manages access log files. IO is performed directly * by AddLog safs. */ -LogFile* get_access_log_file(sstr_t file) { +LogFile* get_access_log_file(scstr_t file) { + // TODO: this looks dubious + if(!access_log_files) { access_log_files = ucx_map_new(4); } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/log.h --- a/src/server/daemon/log.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/log.h Tue Aug 25 12:07:56 2020 +0200 @@ -40,10 +40,10 @@ #endif typedef struct { - char *file; - char *level; - int log_stdout; - int log_stderr; + const char *file; + const char *level; + int log_stdout; + int log_stderr; } LogConfig; typedef struct { @@ -75,7 +75,7 @@ void log_remove_logdup(LogDup *dup); // access logging -LogFile* get_access_log_file(sstr_t file); +LogFile* get_access_log_file(scstr_t file); #ifdef __cplusplus } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/main.c --- a/src/server/daemon/main.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/main.c Tue Aug 25 12:07:56 2020 +0200 @@ -39,7 +39,7 @@ #include "../util/plist.h" #include "../util/date.h" -#include "../../ucx/string.h" +#include #include "webserver.h" #include "log.h" @@ -167,7 +167,7 @@ int status; status = webserver_init(); if(status != 0) { - log_ereport(LOG_FAILURE, "cannot initialize server."); + log_ereport(LOG_FAILURE, "Cannot initialize server."); return EXIT_FAILURE; } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/srvctrl.c --- a/src/server/daemon/srvctrl.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/srvctrl.c Tue Aug 25 12:07:56 2020 +0200 @@ -37,8 +37,8 @@ #include "../util/systhr.h" -#include "../../ucx/utils.h" -#include "../../ucx/buffer.h" +#include +#include #include "srvctrl.h" diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/srvctrl.h --- a/src/server/daemon/srvctrl.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/srvctrl.h Tue Aug 25 12:07:56 2020 +0200 @@ -31,7 +31,7 @@ #include "../public/nsapi.h" -#include "../../ucx/string.h" +#include #include "config.h" diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/threadpools.c --- a/src/server/daemon/threadpools.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/threadpools.c Tue Aug 25 12:07:56 2020 +0200 @@ -45,7 +45,7 @@ static threadpool_t *default_io_pool; static threadpool_t *last_io_pool; -int create_threadpool(sstr_t name, ThreadPoolConfig *cfg) { +int create_threadpool(scstr_t name, ThreadPoolConfig *cfg) { if(thread_pool_map == NULL) { thread_pool_map = ucx_map_new(16); } @@ -77,7 +77,7 @@ } } -int create_io_pool(sstr_t name, int numthreads) { +int create_io_pool(scstr_t name, int numthreads) { if(io_pool_map == NULL) { io_pool_map = ucx_map_new(4); } @@ -110,13 +110,13 @@ cfg.max_threads = 8; cfg.queue_size = 64; cfg.stack_size = 262144; - if(create_threadpool(sstr("default"), &cfg)) { + if(create_threadpool(SC("default"), &cfg)) { return 1; } } if(num_iopools == 0) { - if(create_io_pool(sstr("default"), 8)) { + if(create_io_pool(SC("default"), 8)) { return 1; } } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/threadpools.h --- a/src/server/daemon/threadpools.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/threadpools.h Tue Aug 25 12:07:56 2020 +0200 @@ -45,7 +45,7 @@ int queue_size; } ThreadPoolConfig; -int create_threadpool(sstr_t name, ThreadPoolConfig *cfg); +int create_threadpool(scstr_t name, ThreadPoolConfig *cfg); int check_thread_pool_cfg(); diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/vserver.c --- a/src/server/daemon/vserver.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/vserver.c Tue Aug 25 12:07:56 2020 +0200 @@ -38,23 +38,6 @@ return vs; } -VirtualServer* vs_copy(VirtualServer *vs, pool_handle_t *pool) { - VirtualServer *newvs = malloc(sizeof(VirtualServer)); - newvs->ref = 1; - newvs->document_root = sstrdup_pool(pool, vs->document_root); - newvs->host = sstrdup_pool(pool, vs->host); - newvs->name = sstrdup_pool(pool, vs->name); - newvs->objectfile = sstrdup_pool(pool, vs->objectfile); - newvs->acls = vs->acls; - acl_data_ref(newvs->acls); - newvs->log = vs->log; // TODO: ref - - newvs->objects = vs->objects; - - return newvs; -} - - diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/vserver.h --- a/src/server/daemon/vserver.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/vserver.h Tue Aug 25 12:07:56 2020 +0200 @@ -58,7 +58,6 @@ }; VirtualServer* vs_new(); -VirtualServer* vs_copy(VirtualServer *vs, pool_handle_t *pool); #ifdef __cplusplus diff -r 5653a9626cc0 -r 0b8692959d37 src/server/daemon/webserver.c --- a/src/server/daemon/webserver.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/daemon/webserver.c Tue Aug 25 12:07:56 2020 +0200 @@ -48,7 +48,7 @@ #include "../util/io.h" #include "../util/util.h" -#include "../../ucx/utils.h" +#include #include "../safs/common.h" @@ -87,7 +87,6 @@ init_configuration_manager(); ServerConfiguration *cfg; if(cfgmgr_load_config(&cfg) != 0) { - fprintf(stderr, "Cannot load configuration\n"); return -1; } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/safs/cgi.c --- a/src/server/safs/cgi.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/safs/cgi.c Tue Aug 25 12:07:56 2020 +0200 @@ -36,9 +36,10 @@ #include #include +#include + #include "../util/util.h" #include "../util/pblock.h" -#include "../../ucx/string.h" #include "../daemon/netsite.h" #include "../util/io.h" diff -r 5653a9626cc0 -r 0b8692959d37 src/server/safs/cgi.h --- a/src/server/safs/cgi.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/safs/cgi.h Tue Aug 25 12:07:56 2020 +0200 @@ -30,7 +30,7 @@ #define CGI_H #include "../public/nsapi.h" -#include "../../ucx/buffer.h" +#include #ifdef __cplusplus extern "C" { diff -r 5653a9626cc0 -r 0b8692959d37 src/server/safs/common.c --- a/src/server/safs/common.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/safs/common.c Tue Aug 25 12:07:56 2020 +0200 @@ -33,7 +33,7 @@ #include "../util/pblock.h" #include "../util/util.h" -#include "../../ucx/map.h" +#include static UcxMap *var_names; diff -r 5653a9626cc0 -r 0b8692959d37 src/server/test/main.c diff -r 5653a9626cc0 -r 0b8692959d37 src/server/util/util.c --- a/src/server/util/util.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/util/util.c Tue Aug 25 12:07:56 2020 +0200 @@ -394,7 +394,7 @@ return def; } -int util_getboolean_s(sstr_t s, int def) { +int util_getboolean_s(scstr_t s, int def) { if(s.length == 0) { return def; } diff -r 5653a9626cc0 -r 0b8692959d37 src/server/util/util.h --- a/src/server/util/util.h Fri Jul 24 08:00:11 2020 +0200 +++ b/src/server/util/util.h Tue Aug 25 12:07:56 2020 +0200 @@ -197,7 +197,7 @@ NSAPI_PUBLIC PRBool INTutil_format_http_version(const char *v, int *protv_num, char *buffer, int size); NSAPI_PUBLIC int INTutil_getboolean(const char *v, int def); -int util_getboolean_s(sstr_t s, int def); +int util_getboolean_s(scstr_t s, int def); // new NSAPI_PUBLIC int util_strtoint(char *str, int64_t *value); diff -r 5653a9626cc0 -r 0b8692959d37 src/tools/Makefile --- a/src/tools/Makefile Fri Jul 24 08:00:11 2020 +0200 +++ b/src/tools/Makefile Tue Aug 25 12:07:56 2020 +0200 @@ -30,7 +30,7 @@ include $(BUILD_ROOT)/config.mk -CFLAGS += -I.. +CFLAGS += -I../ucx/ LDFLAGS += -L../../build/lib -lucx -lwscfg # list of source files diff -r 5653a9626cc0 -r 0b8692959d37 src/tools/wstool.c --- a/src/tools/wstool.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/tools/wstool.c Tue Aug 25 12:07:56 2020 +0200 @@ -32,7 +32,7 @@ #include #include -#include "../server/config/serverconf.h" +#include "../server/config/serverconfig.h" #include "srvctrlsocket.h" @@ -61,8 +61,8 @@ } int tool_get_tmpdir(char *configfile) { - ServerConfig *serverconf = load_server_config(configfile); - UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7)); + ServerConfig *serverconf = serverconfig_load(configfile); + UcxList *list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Runtime")); if(!list) { fprintf(stderr, "Error: No Runtime element in %s\n", configfile); return -1; @@ -71,8 +71,11 @@ fprintf(stderr, "Error: Multiple Runtime elements in %s\n", configfile); return -1; } - ServerConfigObject *runtime = list->data; - sstr_t tmp = cfg_directivelist_get_str(runtime->directives, sstr("Temp")); + ConfigNode *runtime = list->data; + scstr_t tmp = serverconfig_directive_value(runtime, SC("Temp")); + + ucx_list_free(list); + if(!tmp.ptr) { fprintf(stderr, "Error: No Temp directive in Runtime Object\n"); return -1; diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/Makefile --- a/src/ucx/Makefile Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/Makefile Tue Aug 25 12:07:56 2020 +0200 @@ -31,7 +31,8 @@ include $(BUILD_ROOT)/config.mk # list of source files -SRC = utils.c +SRC = ucx.c +SRC += utils.c SRC += list.c SRC += map.c SRC += avl.c @@ -43,6 +44,7 @@ SRC += logging.c SRC += buffer.c SRC += stack.c +SRC += array.c OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/ucx/%$(OBJ_EXT)) diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/allocator.c --- a/src/ucx/allocator.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/allocator.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,10 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "ucx/allocator.h" + #include -#include "allocator.h" -UcxAllocator default_allocator = { +static UcxAllocator default_allocator = { NULL, ucx_default_malloc, ucx_default_calloc, diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/allocator.h --- a/src/ucx/allocator.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Allocator for custom memory management. - * - * A UCX allocator consists of a pointer to the memory area / pool and four - * function pointers to memory management functions operating on this memory - * area / pool. These functions shall behave equivalent to the standard libc - * functions malloc(), calloc(), realloc() and free(). - * - * The signature of the memory management functions is based on the signature - * of the respective libc function but each of them takes the pointer to the - * memory area / pool as first argument. - * - * As the pointer to the memory area / pool can be arbitrarily chosen, any data - * can be provided to the memory management functions. A UcxMempool is just - * one example. - * - * @see mempool.h - * @see UcxMap - * - * @file allocator.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_ALLOCATOR_H -#define UCX_ALLOCATOR_H - -#include "ucx.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * A function pointer to the allocators malloc() function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); - -/** - * A function pointer to the allocators calloc() function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); - -/** - * A function pointer to the allocators realloc() function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); - -/** - * A function pointer to the allocators free() function. - * @see UcxAllocator - */ -typedef void(*ucx_allocator_free)(void *pool, void *data); - -/** - * UCX allocator data structure containing memory management functions. - */ -typedef struct { - /** Pointer to an area of memory or a complex memory pool. - * This pointer will be passed to any memory management function as first - * argument. - */ - void *pool; - /** - * The malloc() function for this allocator. - */ - ucx_allocator_malloc malloc; - /** - * The calloc() function for this allocator. - */ - ucx_allocator_calloc calloc; - /** - * The realloc() function for this allocator. - */ - ucx_allocator_realloc realloc; - /** - * The free() function for this allocator. - */ - ucx_allocator_free free; -} UcxAllocator; - -/** - * Returns a pointer to the default allocator. - * - * The default allocator contains wrappers to the standard libc memory - * management functions. Use this function to get a pointer to a globally - * available allocator. You may also define an own UcxAllocator by assigning - * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable - * to any function that takes a UcxAllocator as argument. Note that using - * this function is the recommended way of passing a default allocator, thus - * it never runs out of scope. - * - * @return a pointer to the default allocator - * - * @see UCX_ALLOCATOR_DEFAULT - */ -UcxAllocator *ucx_default_allocator(); - -/** - * A wrapper for the standard libc malloc() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param n argument passed to malloc() - * @return return value of malloc() - */ -void *ucx_default_malloc(void *ignore, size_t n); -/** - * A wrapper for the standard libc calloc() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param n argument passed to calloc() - * @param size argument passed to calloc() - * @return return value of calloc() - */ -void *ucx_default_calloc(void *ignore, size_t n, size_t size); -/** - * A wrapper for the standard libc realloc() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param data argumend passed to realloc() - * @param n argument passed to realloc() - * @return return value of realloc() - */ -void *ucx_default_realloc(void *ignore, void *data, size_t n); -/** - * A wrapper for the standard libc free() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param data argument passed to free() - */ -void ucx_default_free(void *ignore, void *data); - -/** - * Shorthand for calling an allocators malloc function. - * @param allocator the allocator to use - * @param n size of space to allocate - * @return a pointer to the allocated memory area - */ -#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n)) - -/** - * Shorthand for calling an allocators calloc function. - * @param allocator the allocator to use - * @param n the count of elements the space should be allocated for - * @param size the size of each element - * @return a pointer to the allocated memory area - */ -#define alcalloc(allocator, n, size) \ - ((allocator)->calloc((allocator)->pool, n, size)) - -/** - * Shorthand for calling an allocators realloc function. - * @param allocator the allocator to use - * @param ptr the pointer to the memory area that shall be reallocated - * @param n the new size of the allocated memory area - * @return a pointer to the reallocated memory area - */ -#define alrealloc(allocator, ptr, n) \ - ((allocator)->realloc((allocator)->pool, ptr, n)) - -/** - * Shorthand for calling an allocators free function. - * @param allocator the allocator to use - * @param ptr the pointer to the memory area that shall be freed - */ -#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr)) - -/** - * Convenient macro for a default allocator struct definition. - */ -#define UCX_ALLOCATOR_DEFAULT {NULL, \ - ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \ - ucx_default_free } - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_ALLOCATOR_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/array.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/array.c Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,488 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2019 Mike Becker, 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. + */ + +#define _GNU_SOURCE /* we want to use qsort_r(), if available */ +#define __STDC_WANT_LIB_EXT1__ 1 /* use qsort_s, if available */ + + +#include "ucx/array.h" +#include "ucx/utils.h" + +#include +#include +#include + +#ifndef UCX_ARRAY_DISABLE_QSORT +#ifdef __GLIBC__ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +#define ucx_array_sort_impl qsort_r +#endif /* glibc version >= 2.8 */ +#elif /* not __GLIBC__ */ defined(__APPLE__) || defined(__FreeBSD__) +#define ucx_array_sort_impl ucx_qsort_r +#define USE_UCX_QSORT_R +#elif /* not (__APPLE || __FreeBSD__) */ defined(__sun) +#if __STDC_VERSION__ >= 201112L +#define ucx_array_sort_impl qsort_s +#endif +#endif /* __GLIBC__, __APLE__, __FreeBSD__, __sun */ +#endif /* UCX_ARRAY_DISABLE_QSORT */ + +#ifndef ucx_array_sort_impl +#define ucx_array_sort_impl ucx_mergesort +#endif + +static int ucx_array_ensurecap(UcxArray *array, size_t reqcap) { + size_t required_capacity = array->capacity; + while (reqcap > required_capacity) { + if (required_capacity * 2 < required_capacity) + return 1; + required_capacity <<= 1; + } + if (ucx_array_reserve(array, required_capacity)) { + return 1; + } + return 0; +} + +int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t elmsize, size_t index, ...) { + + if(!alloc || !capacity || !array) { + errno = EINVAL; + return 1; + } + + size_t newcapacity = *capacity; + while(index >= newcapacity) { + if(ucx_szmul(newcapacity, 2, &newcapacity)) { + errno = EOVERFLOW; + return 1; + } + } + + size_t memlen, offset; + if(ucx_szmul(newcapacity, elmsize, &memlen)) { + errno = EOVERFLOW; + return 1; + } + /* we don't need to check index*elmsize - it is smaller than memlen */ + + + void* newptr = alrealloc(alloc, *array, memlen); + if(newptr == NULL) { + errno = ENOMEM; /* we cannot assume that every allocator sets this */ + return 1; + } + *array = newptr; + *capacity = newcapacity; + + + 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); + + return 0; +} + +UcxArray* ucx_array_new(size_t capacity, size_t elemsize) { + return ucx_array_new_a(capacity, elemsize, ucx_default_allocator()); +} + +UcxArray* ucx_array_new_a(size_t capacity, size_t elemsize, + UcxAllocator* allocator) { + UcxArray* array = almalloc(allocator, sizeof(UcxArray)); + if(array) { + ucx_array_init_a(array, capacity, elemsize, allocator); + } + return array; +} + +void ucx_array_init(UcxArray* array, size_t capacity, size_t elemsize) { + ucx_array_init_a(array, capacity, elemsize, ucx_default_allocator()); +} + +void ucx_array_init_a(UcxArray* array, size_t capacity, size_t elemsize, + UcxAllocator* allocator) { + + array->allocator = allocator; + array->elemsize = elemsize; + array->size = 0; + array->data = alcalloc(allocator, capacity, elemsize); + + if (array->data) { + array->capacity = capacity; + } else { + array->capacity = 0; + } +} + +int ucx_array_clone(UcxArray* dest, UcxArray const* src) { + if (ucx_array_ensurecap(dest, src->capacity)) { + return 1; + } + + dest->elemsize = src->elemsize; + dest->size = src->size; + + if (dest->data) { + memcpy(dest->data, src->data, src->size*src->elemsize); + } + + return 0; +} + +int ucx_array_equals(UcxArray const *array1, UcxArray const *array2, + cmp_func cmpfnc, void* data) { + + if (array1->size != array2->size || array1->elemsize != array2->elemsize) { + return 0; + } else { + if (array1->size == 0) + return 1; + + size_t elemsize; + if (cmpfnc == NULL) { + cmpfnc = ucx_cmp_mem; + elemsize = array1->elemsize; + data = &elemsize; + } + + for (size_t i = 0 ; i < array1->size ; i++) { + int r = cmpfnc( + ucx_array_at(array1, i), + ucx_array_at(array2, i), + data); + if (r != 0) + return 0; + } + return 1; + } +} + +void ucx_array_destroy(UcxArray *array) { + if(array->data) + alfree(array->allocator, array->data); + array->data = NULL; + array->capacity = array->size = 0; +} + +void ucx_array_free(UcxArray *array) { + ucx_array_destroy(array); + alfree(array->allocator, array); +} + +int ucx_array_append_from(UcxArray *array, void *data, size_t count) { + if (ucx_array_ensurecap(array, array->size + count)) + return 1; + + void* dest = ucx_array_at(array, array->size); + if (data) { + memcpy(dest, data, array->elemsize*count); + } else { + memset(dest, 0, array->elemsize*count); + } + array->size += count; + + return 0; +} + +int ucx_array_prepend_from(UcxArray *array, void *data, size_t count) { + if (ucx_array_ensurecap(array, array->size + count)) + return 1; + + if (array->size > 0) { + void *dest = ucx_array_at(array, count); + memmove(dest, array->data, array->elemsize*array->size); + } + + if (data) { + memcpy(array->data, data, array->elemsize*count); + } else { + memset(array->data, 0, array->elemsize*count); + } + array->size += count; + + return 0; +} + +int ucx_array_set_from(UcxArray *array, size_t index, + void *data, size_t count) { + if (ucx_array_ensurecap(array, index + count)) + return 1; + + if (index+count > array->size) { + array->size = index+count; + } + + void *dest = ucx_array_at(array, index); + if (data) { + memcpy(dest, data, array->elemsize*count); + } else { + memset(dest, 0, array->elemsize*count); + } + + 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) + return 1; + + size_t capacity = array1->capacity+array2->capacity; + + if (array1->capacity < capacity) { + if (ucx_array_reserve(array1, capacity)) { + return 1; + } + } + + void* dest = ucx_array_at(array1, array1->size); + memcpy(dest, array2->data, array2->size*array2->elemsize); + + array1->size += array2->size; + + return 0; +} + +void *ucx_array_at(UcxArray const *array, size_t index) { + char* memory = array->data; + char* loc = memory + index*array->elemsize; + return loc; +} + +size_t ucx_array_find(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data) { + + size_t elemsize; + if (cmpfnc == NULL) { + cmpfnc = ucx_cmp_mem; + elemsize = array->elemsize; + data = &elemsize; + } + + if (array->size > 0) { + for (size_t i = 0 ; i < array->size ; i++) { + void* ptr = ucx_array_at(array, i); + if (cmpfnc(ptr, elem, data) == 0) { + return i; + } + } + return array->size; + } else { + return 0; + } +} + +int ucx_array_contains(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data) { + return ucx_array_find(array, elem, cmpfnc, data) != array->size; +} + +static void ucx_mergesort_merge(void *arrdata,size_t elemsize, + cmp_func cmpfnc, void *data, + size_t start, size_t mid, size_t end) { + + char* array = arrdata; + + size_t rightstart = mid + 1; + + if (cmpfnc(array + mid*elemsize, + array + rightstart*elemsize, data) <= 0) { + /* already sorted */ + return; + } + + /* we need memory for one element */ + void *value = malloc(elemsize); + + while (start <= mid && rightstart <= end) { + if (cmpfnc(array + start*elemsize, + array + rightstart*elemsize, data) <= 0) { + start++; + } else { + /* save the value from the right */ + memcpy(value, array + rightstart*elemsize, elemsize); + + /* shift all left elements one element to the right */ + size_t shiftcount = rightstart-start; + void *startptr = array + start*elemsize; + void *dest = array + (start+1)*elemsize; + memmove(dest, startptr, shiftcount*elemsize); + + /* bring the first value from the right to the left */ + memcpy(startptr, value, elemsize); + + start++; + mid++; + rightstart++; + } + } + + /* free the temporary memory */ + free(value); +} + +static void ucx_mergesort_impl(void *arrdata, size_t elemsize, + cmp_func cmpfnc, void *data, size_t l, size_t r) { + if (l < r) { + size_t m = l + (r - l) / 2; + + ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, l, m); + ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, m + 1, r); + ucx_mergesort_merge(arrdata, elemsize, cmpfnc, data, l, m, r); + } +} + +static void ucx_mergesort(void *arrdata, size_t count, size_t elemsize, + cmp_func cmpfnc, void *data) { + + ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, 0, count-1); +} + +#ifdef USE_UCX_QSORT_R +struct cmpfnc_swapargs_info { + cmp_func func; + void *data; +}; + +static int cmp_func_swap_args(void *data, const void *x, const void *y) { + cmpfnc_swapargs_info* info = data; + return info->func(x, y, info->data); +} + +static void ucx_qsort_r(void *array, size_t count, size_t elemsize, + cmp_func cmpfnc, void *data) { + struct cmpfnc_swapargs_info info; + info.func = cmpfnc; + info.data = data; + qsort_r(array, count, elemsize, &info, cmp_func_swap_args); +} +#endif /* USE_UCX_QSORT_R */ + +void ucx_array_sort(UcxArray* array, cmp_func cmpfnc, void *data) { + ucx_array_sort_impl(array->data, array->size, array->elemsize, + cmpfnc, data); +} + +void ucx_array_remove(UcxArray *array, size_t index) { + array->size--; + if (index < array->size) { + void* dest = ucx_array_at(array, index); + void* src = ucx_array_at(array, index+1); + memmove(dest, src, (array->size - index)*array->elemsize); + } +} + +void ucx_array_remove_fast(UcxArray *array, size_t index) { + array->size--; + if (index < array->size) { + void* dest = ucx_array_at(array, index); + void* src = ucx_array_at(array, array->size); + memcpy(dest, src, array->elemsize); + } +} + +int ucx_array_shrink(UcxArray* array) { + void* newptr = alrealloc(array->allocator, array->data, + array->size*array->elemsize); + if (newptr) { + array->data = newptr; + array->capacity = array->size; + return 0; + } else { + return 1; + } +} + +int ucx_array_resize(UcxArray* array, size_t capacity) { + if (array->capacity >= capacity) { + void* newptr = alrealloc(array->allocator, array->data, + capacity*array->elemsize); + if (newptr) { + array->data = newptr; + array->capacity = capacity; + if (array->size > array->capacity) { + array->size = array->capacity; + } + return 0; + } else { + return 1; + } + } else { + return ucx_array_reserve(array, capacity); + } +} + +int ucx_array_reserve(UcxArray* array, size_t capacity) { + if (array->capacity > capacity) { + return 0; + } else { + void* newptr = alrealloc(array->allocator, array->data, + capacity*array->elemsize); + if (newptr) { + array->data = newptr; + array->capacity = capacity; + return 0; + } else { + return 1; + } + } +} diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/avl.c --- a/src/ucx/avl.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/avl.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,7 +26,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "avl.h" +#include "ucx/avl.h" + +#include #define ptrcast(ptr) ((void*)(ptr)) #define alloc_tree(al) (UcxAVLTree*) almalloc((al), sizeof(UcxAVLTree)) @@ -134,6 +136,23 @@ alfree(al, tree); } +static void ucx_avl_free_content_node(UcxAllocator *al, UcxAVLNode *node, + ucx_destructor destr) { + if (node) { + ucx_avl_free_content_node(al, node->left, destr); + ucx_avl_free_content_node(al, node->right, destr); + if (destr) { + destr(node->value); + } else { + alfree(al, node->value); + } + } +} + +void ucx_avl_free_content(UcxAVLTree *tree, ucx_destructor destr) { + ucx_avl_free_content_node(tree->allocator, tree->root, destr); +} + UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) { UcxAVLNode *n = tree->root; int cmpresult; @@ -149,6 +168,46 @@ return n ? n->value : NULL; } +UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode) { + UcxAVLNode *n = tree->root; + UcxAVLNode *closest = NULL; + + intmax_t cmpresult; + intmax_t closest_dist; + closest_dist = mode == UCX_AVL_FIND_LOWER_BOUNDED ? INTMAX_MIN : INTMAX_MAX; + + while (n && (cmpresult = dfnc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + if (mode == UCX_AVL_FIND_CLOSEST) { + intmax_t dist = cmpresult; + if (dist < 0) dist *= -1; + if (dist < closest_dist) { + closest_dist = dist; + closest = n; + } + } else if (mode == UCX_AVL_FIND_LOWER_BOUNDED && cmpresult <= 0) { + if (cmpresult > closest_dist) { + closest_dist = cmpresult; + closest = n; + } + } else if (mode == UCX_AVL_FIND_UPPER_BOUNDED && cmpresult >= 0) { + if (cmpresult < closest_dist) { + closest_dist = cmpresult; + closest = n; + } + } + n = cmpresult > 0 ? n->right : n->left; + } + return n ? n : closest; +} + +void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode) { + UcxAVLNode *n = ucx_avl_find_node(tree, key, dfnc, mode); + return n ? n->value : NULL; +} + int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) { return ucx_avl_put_s(tree, key, value, NULL); } @@ -272,3 +331,43 @@ size_t ucx_avl_count(UcxAVLTree *tree) { return ucx_avl_countn(tree->root); } + +UcxAVLNode* ucx_avl_pred(UcxAVLNode* node) { + if (node->left) { + UcxAVLNode* n = node->left; + while (n->right) { + n = n->right; + } + return n; + } else { + UcxAVLNode* n = node; + while (n->parent) { + if (n->parent->right == n) { + return n->parent; + } else { + n = n->parent; + } + } + return NULL; + } +} + +UcxAVLNode* ucx_avl_succ(UcxAVLNode* node) { + if (node->right) { + UcxAVLNode* n = node->right; + while (n->left) { + n = n->left; + } + return n; + } else { + UcxAVLNode* n = node; + while (n->parent) { + if (n->parent->left == n) { + return n->parent; + } else { + n = n->parent; + } + } + return NULL; + } +} diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/avl.h --- a/src/ucx/avl.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,249 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -/** - * @file avl.h - * - * AVL tree implementation. - * - * This binary search tree implementation allows average O(1) insertion and - * removal of elements (excluding binary search time). - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_AVL_H -#define UCX_AVL_H - -#include "ucx.h" -#include "allocator.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * UCX AVL Node type. - * - * @see UcxAVLNode - */ -typedef struct UcxAVLNode UcxAVLNode; - -/** - * UCX AVL Node. - */ -struct UcxAVLNode { - /** - * The key for this node. - */ - intptr_t key; - /** - * Data contained by this node. - */ - void *value; - /** - * The height of this (sub)-tree. - */ - size_t height; - /** - * Parent node. - */ - UcxAVLNode *parent; - /** - * Root node of left subtree. - */ - UcxAVLNode *left; - /** - * Root node of right subtree. - */ - UcxAVLNode *right; -}; - -/** - * UCX AVL Tree. - */ -typedef struct { - /** - * The UcxAllocator that shall be used to manage the memory for node data. - */ - UcxAllocator *allocator; - /** - * Root node of the tree. - */ - UcxAVLNode *root; - /** - * Compare function that shall be used to compare the UcxAVLNode keys. - * @see UcxAVLNode.key - */ - cmp_func cmpfunc; - /** - * Custom user data. - * This data will also be provided to the cmpfunc. - */ - void *userdata; -} UcxAVLTree; - -/** - * Initializes a new UcxAVLTree with a default allocator. - * - * @param cmpfunc the compare function that shall be used - * @return a new UcxAVLTree object - * @see ucx_avl_new_a() - */ -UcxAVLTree *ucx_avl_new(cmp_func cmpfunc); - -/** - * Initializes a new UcxAVLTree with the specified allocator. - * - * The cmpfunc should be capable of comparing two keys within this AVL tree. - * So if you want to use null terminated strings as keys, you could use the - * ucx_strcmp() function here. - * - * @param cmpfunc the compare function that shall be used - * @param allocator the UcxAllocator that shall be used - * @return a new UcxAVLTree object - */ -UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator); - -/** - * Destroys a UcxAVLTree. - * @param tree the tree to destroy - */ -void ucx_avl_free(UcxAVLTree *tree); - -/** - * Macro for initializing a new UcxAVLTree with the default allocator and a - * ucx_ptrcmp() compare function. - * - * @return a new default UcxAVLTree object - */ -#define ucx_avl_default_new() ucx_avl_new_a(ucx_ptrcmp, ucx_default_allocator()) - -/** - * Gets the node from the tree, that is associated with the specified key. - * @param tree the UcxAVLTree - * @param key the key - * @return the node (or NULL, if the key is not present) - */ -UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key); - -/** - * Gets the value from the tree, that is associated with the specified key. - * @param tree the UcxAVLTree - * @param key the key - * @return the value (or NULL, if the key is not present) - */ -void *ucx_avl_get(UcxAVLTree *tree, intptr_t key); - -/** - * Puts a key/value pair into the tree. - * - * Attention: use this function only, if a possible old value does not need - * to be preserved. - * - * @param tree the UcxAVLTree - * @param key the key - * @param value the new value - * @return zero, if and only if the operation succeeded - */ -int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value); - -/** - * Puts a key/value pair into the tree. - * - * This is a secure function which saves the old value to the variable pointed - * at by oldvalue. - * - * @param tree the UcxAVLTree - * @param key the key - * @param value the new value - * @param oldvalue optional: a pointer to the location where a possible old - * value shall be stored - * @return zero, if and only if the operation succeeded - */ -int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, void **oldvalue); - -/** - * Removes a node from the AVL tree. - * - * Note: the specified node is logically removed. The tree implementation - * decides which memory area is freed. In most cases the here provided node - * is freed, so it's further use is generally undefined. - * - * @param tree the UcxAVLTree - * @param node the node to remove - * @return zero, if and only if an element has been removed - */ -int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node); - -/** - * Removes an element from the AVL tree. - * - * @param tree the UcxAVLTree - * @param key the key - * @return zero, if and only if an element has been removed - */ -int ucx_avl_remove(UcxAVLTree *tree, intptr_t key); - -/** - * Removes an element from the AVL tree. - * - * This is a secure function which saves the old key and value data from node - * to the variables at the location of oldkey and oldvalue (if specified), so - * they can be freed afterwards (if necessary). - * - * Note: the returned key in oldkey is possibly not the same as the provided - * key for the lookup (in terms of memory location). - * - * @param tree the UcxAVLTree - * @param key the key of the element to remove - * @param oldkey optional: a pointer to the location where the old key shall be - * stored - * @param oldvalue optional: a pointer to the location where the old value - * shall be stored - * @return zero, if and only if an element has been removed - */ -int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, - intptr_t *oldkey, void **oldvalue); - -/** - * Counts the nodes in the specified UcxAVLTree. - * @param tree the AVL tree - * @return the node count - */ -size_t ucx_avl_count(UcxAVLTree *tree); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_AVL_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/buffer.c --- a/src/ucx/buffer.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/buffer.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,7 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "buffer.h" +#include "ucx/buffer.h" + #include #include #include @@ -64,8 +65,9 @@ UcxBuffer* ucx_buffer_extract( UcxBuffer *src, size_t start, size_t length, int flags) { - - if (src->size == 0 || length == 0 || start+length > src->capacity) { + if (src->size == 0 || length == 0 || + ((size_t)-1) - start < length || start+length > src->capacity) + { return NULL; } @@ -149,7 +151,10 @@ size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, UcxBuffer *buffer) { - size_t len = size * nitems; + size_t len; + if(ucx_szmul(size, nitems, &len)) { + return 0; + } size_t required = buffer->pos + len; if (buffer->pos > required) { return 0; @@ -183,7 +188,10 @@ size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, UcxBuffer *buffer) { - size_t len = size * nitems; + size_t len; + if(ucx_szmul(size, nitems, &len)) { + return 0; + } if (buffer->pos + len > buffer->size) { len = buffer->size - buffer->pos; if (size > 1) len -= len%size; @@ -223,12 +231,67 @@ if (ucx_buffer_eof(buffer)) { return EOF; } else { - int c = buffer->space[buffer->pos]; + int c = ((unsigned char*)buffer->space)[buffer->pos]; buffer->pos++; return c; } } -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) { +size_t ucx_buffer_puts(UcxBuffer *buffer, const char *str) { return ucx_buffer_write((const void*)str, 1, strlen(str), buffer); } + +int ucx_buffer_shift_left(UcxBuffer* buffer, size_t shift) { + if (shift >= buffer->size) { + buffer->pos = buffer->size = 0; + } else { + memmove(buffer->space, buffer->space + shift, buffer->size - shift); + buffer->size -= shift; + + if (buffer->pos >= shift) { + buffer->pos -= shift; + } else { + buffer->pos = 0; + } + } + return 0; +} + +int ucx_buffer_shift_right(UcxBuffer* buffer, size_t shift) { + size_t req_capacity = buffer->size + shift; + size_t movebytes; + + // auto extend buffer, if required and enabled + if (buffer->capacity < req_capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if (ucx_buffer_extend(buffer, req_capacity - buffer->capacity)) { + return 1; + } + movebytes = buffer->size; + } else { + movebytes = buffer->capacity - shift; + } + } else { + movebytes = buffer->size; + } + + memmove(buffer->space + shift, buffer->space, movebytes); + buffer->size = shift+movebytes; + + buffer->pos += shift; + if (buffer->pos > buffer->size) { + buffer->pos = buffer->size; + } + + return 0; +} + +int ucx_buffer_shift(UcxBuffer* buffer, off_t shift) { + if (shift < 0) { + return ucx_buffer_shift_left(buffer, (size_t) (-shift)); + } else if (shift > 0) { + return ucx_buffer_shift_right(buffer, (size_t) shift); + } else { + return 0; + } +} diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/buffer.h --- a/src/ucx/buffer.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file buffer.h - * - * Advanced buffer implementation. - * - * Instances of UcxBuffer can be used to read from or to write to like one - * would do with a stream. This allows the use of ucx_stream_copy() to copy - * contents from one buffer to another. - * - * Some features for convenient use of the buffer - * can be enabled. See the documentation of the macro constants for more - * information. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_BUFFER_H -#define UCX_BUFFER_H - -#include "ucx.h" -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * No buffer features enabled (all flags cleared). - */ -#define UCX_BUFFER_DEFAULT 0x00 - -/** - * If this flag is enabled, the buffer will automatically free its contents. - */ -#define UCX_BUFFER_AUTOFREE 0x01 - -/** - * If this flag is enabled, the buffer will automatically extends its capacity. - */ -#define UCX_BUFFER_AUTOEXTEND 0x02 - -/** UCX Buffer. */ -typedef struct { - /** A pointer to the buffer contents. */ - char *space; - /** Current position of the buffer. */ - size_t pos; - /** Current capacity (i.e. maximum size) of the buffer. */ - size_t capacity; - /** Current size of the buffer content. */ - size_t size; - /** - * Flag register for buffer features. - * @see #UCX_BUFFER_DEFAULT - * @see #UCX_BUFFER_AUTOFREE - * @see #UCX_BUFFER_AUTOEXTEND - */ - int flags; -} UcxBuffer; - -/** - * Creates a new buffer. - * - * Note: you may provide NULL as argument for - * space. Then this function will allocate the space and enforce - * the #UCX_BUFFER_AUTOFREE flag. - * - * @param space pointer to the memory area, or NULL to allocate - * new memory - * @param capacity the capacity of the buffer - * @param flags buffer features (see UcxBuffer.flags) - * @return the new buffer - */ -UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); - -/** - * Destroys a buffer. - * - * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer - * are also freed. - * - * @param buffer the buffer to destroy - */ -void ucx_buffer_free(UcxBuffer* buffer); - -/** - * Creates a new buffer and fills it with extracted content from another buffer. - * - * Note: the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. - * - * @param src the source buffer - * @param start the start position of extraction - * @param length the count of bytes to extract (must not be zero) - * @param flags feature mask for the new buffer - * @return a new buffer containing the extraction - */ -UcxBuffer* ucx_buffer_extract(UcxBuffer *src, - size_t start, size_t length, int flags); - -/** - * A shorthand macro for the full extraction of the buffer. - * - * @param src the source buffer - * @param flags feature mask for the new buffer - * @return a new buffer with the extracted content - */ -#define ucx_buffer_clone(src,flags) \ - ucx_buffer_extract(src, 0, (src)->capacity, flags) - -/** - * Moves the position of the buffer. - * - * The new position is relative to the whence argument. - * - * SEEK_SET marks the start of the buffer. - * SEEK_CUR marks the current position. - * SEEK_END marks the end of the buffer. - * - * With an offset of zero, this function sets the buffer position to zero - * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position - * unchanged (SEEK_CUR). - * - * @param buffer - * @param offset position offset relative to whence - * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END - * @return 0 on success, non-zero if the position is invalid - * - */ -int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); - -/** - * Clears the buffer by resetting the position and deleting the data. - * - * The data is deleted by a zeroing it with call to memset(). - * - * @param buffer the buffer to be cleared - */ -#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ - buffer->size = 0; buffer->pos = 0; - -/** - * Tests, if the buffer position has exceeded the buffer capacity. - * - * @param buffer the buffer to test - * @return non-zero, if the current buffer position has exceeded the last - * available byte of the buffer. - */ -int ucx_buffer_eof(UcxBuffer *buffer); - - -/** - * Extends the capacity of the buffer. - * - * Note: The buffer capacity increased by a power of two. I.e. - * the buffer capacity is doubled, as long as it would not hold the current - * content plus the additional required bytes. - * - * Attention: the argument provided is the number of additional - * bytes the buffer shall hold. It is NOT the total number of bytes the - * buffer shall hold. - * - * @param buffer the buffer to extend - * @param additional_bytes the number of additional bytes the buffer shall - * at least hold - * @return 0 on success or a non-zero value on failure - */ -int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); - -/** - * Writes data to a UcxBuffer. - * - * The position of the buffer is increased by the number of bytes written. - * - * @param ptr a pointer to the memory area containing the bytes to be written - * @param size the length of one element - * @param nitems the element count - * @param buffer the UcxBuffer to write to - * @return the total count of bytes written - */ -size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer); - -/** - * Reads data from a UcxBuffer. - * - * The position of the buffer is increased by the number of bytes read. - * - * @param ptr a pointer to the memory area where to store the read data - * @param size the length of one element - * @param nitems the element count - * @param buffer the UcxBuffer to read from - * @return the total number of elements read - */ -size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer); - -/** - * Writes a character to a buffer. - * - * The least significant byte of the argument is written to the buffer. If the - * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, - * the buffer capacity is extended by ucx_buffer_extend(). If the feature is - * disabled or buffer extension fails, EOF is returned. - * - * On successful write the position of the buffer is increased. - * - * @param buffer the buffer to write to - * @param c the character to write as int value - * @return the byte that has bean written as int value or - * EOF when the end of the stream is reached and automatic - * extension is not enabled or not possible - */ -int ucx_buffer_putc(UcxBuffer *buffer, int c); - -/** - * Gets a character from a buffer. - * - * The current position of the buffer is increased after a successful read. - * - * @param buffer the buffer to read from - * @return the character as int value or EOF, if the - * end of the buffer is reached - */ -int ucx_buffer_getc(UcxBuffer *buffer); - -/** - * Writes a string to a buffer. - * - * @param buffer the buffer - * @param str the string - * @return the number of bytes written - */ -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_BUFFER_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/list.c --- a/src/ucx/list.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/list.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "list.h" +#include "ucx/list.h" UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); @@ -77,6 +77,7 @@ } void ucx_list_free_content(UcxList* list, ucx_destructor destr) { + if (!destr) destr = free; while (list != NULL) { destr(list->data); list = list->next; @@ -205,15 +206,15 @@ return s; } -static UcxList *ucx_list_sort_merge(int length, - UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, +static UcxList *ucx_list_sort_merge(size_t length, + UcxList* ls, UcxList* le, UcxList* re, cmp_func fnc, void* data) { UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); UcxList *rc, *lc; lc = ls; rc = le; - int n = 0; + size_t n = 0; while (lc && lc != le && rc != re) { if (fnc(lc->data, rc->data, data) <= 0) { sorted[n] = lc; @@ -254,9 +255,9 @@ } UcxList *lc; - int ln = 1; + size_t ln = 1; - UcxList *restrict ls = l, *restrict le, *restrict re; + UcxList *ls = l, *le, *re; // check how many elements are already sorted lc = ls; @@ -270,7 +271,7 @@ return l; // this list is already sorted :) } else { UcxList *rc; - int rn = 1; + size_t rn = 1; rc = le; // skip already sorted elements while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/list.h --- a/src/ucx/list.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Doubly linked list implementation. - * - * @file list.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_LIST_H -#define UCX_LIST_H - -#include "ucx.h" -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Loop statement for UCX lists. - * - * The first argument is the name of the iteration variable. The scope of - * this variable is limited to the UCX_FOREACH statement. - * - * The second argument is a pointer to the list. In most cases this will be the - * pointer to the first element of the list, but it may also be an arbitrary - * element of the list. The iteration will then start with that element. - * - * @param list The first element of the list - * @param elem The variable name of the element - */ -#define UCX_FOREACH(elem,list) \ - for (UcxList* elem = list ; elem != NULL ; elem = elem->next) - -/** - * UCX list type. - * @see UcxList - */ -typedef struct UcxList UcxList; - -/** - * UCX list structure. - */ -struct UcxList { - /** - * List element payload. - */ - void *data; - /** - * Pointer to the next list element or NULL, if this is the - * last element. - */ - UcxList *next; - /** - * Pointer to the previous list element or NULL, if this is - * the first element. - */ - UcxList *prev; -}; - -/** - * Creates an element-wise copy of a list. - * - * This function clones the specified list by creating new list elements and - * copying the data with the specified copy_func(). If no copy_func() is - * specified, a shallow copy is created and the new list will reference the - * same data as the source list. - * - * @param list the list to copy - * @param cpyfnc a pointer to the function that shall copy an element (may be - * NULL) - * @param data additional data for the copy_func() - * @return a pointer to the copy - */ -UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); - -/** - * Creates an element-wise copy of a list using a UcxAllocator. - * - * See ucx_list_clone() for details. - * - * You might want to pass the allocator via the data parameter, - * to access it within the copy function for making deep copies. - * - * @param allocator the allocator to use - * @param list the list to copy - * @param cpyfnc a pointer to the function that shall copy an element (may be - * NULL) - * @param data additional data for the copy_func() - * @return a pointer to the copy - * @see ucx_list_clone() - */ -UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, - copy_func cpyfnc, void* data); - -/** - * Compares two UCX lists element-wise by using a compare function. - * - * Each element of the two specified lists are compared by using the specified - * compare function and the additional data. The type and content of this - * additional data depends on the cmp_func() used. - * - * If the list pointers denote elements within a list, the lists are compared - * starting with the denoted elements. Thus any previous elements are not taken - * into account. This might be useful to check, if certain list tails match - * each other. - * - * @param list1 the first list - * @param list2 the second list - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return 1, if and only if the two lists equal element-wise, 0 otherwise - */ -int ucx_list_equals(const UcxList *list1, const UcxList *list2, - cmp_func cmpfnc, void* data); - -/** - * Destroys the entire list. - * - * The members of the list are not automatically freed, so ensure they are - * otherwise referenced or destroyed by ucx_list_free_contents(). - * Otherwise, a memory leak is likely to occur. - * - * Caution: the argument MUST denote an entire list (i.e. a call - * to ucx_list_first() on the argument must return the argument itself) - * - * @param list the list to free - * @see ucx_list_free_contents() - */ -void ucx_list_free(UcxList *list); - -/** - * Destroys the entire list using a UcxAllocator. - * - * See ucx_list_free() for details. - * - * @param allocator the allocator to use - * @param list the list to free - * @see ucx_list_free() - */ -void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); - -/** - * Destroys the contents of the specified list by calling the specified - * destructor on each of them. - * - * Note, that the contents are not usable afterwards and the list should be - * destroyed with ucx_list_free(). - * - * @param list the list for which the contents shall be freed - * @param destr the destructor function (e.g. stdlib free()) - * @see ucx_list_free() - */ -void ucx_list_free_content(UcxList* list, ucx_destructor destr); - - -/** - * Inserts an element at the end of the list. - * - * This is generally an O(n) operation, as the end of the list is retrieved with - * ucx_list_last(). - * - * @param list the list where to append the data, or NULL to - * create a new list - * @param data the data to insert - * @return list, if it is not NULL or a pointer to - * the newly created list otherwise - */ -UcxList *ucx_list_append(UcxList *list, void *data); - -/** - * Inserts an element at the end of the list using a UcxAllocator. - * - * See ucx_list_append() for details. - * - * @param allocator the allocator to use - * @param list the list where to append the data, or NULL to - * create a new list - * @param data the data to insert - * @return list, if it is not NULL or a pointer to - * the newly created list otherwise - * @see ucx_list_append() - */ -UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); - -/** - * Inserts an element at the beginning of the list. - * - * You should overwrite the old list pointer by calling - * mylist = ucx_list_prepend(mylist, mydata);. However, you may - * also perform successive calls of ucx_list_prepend() on the same list pointer, - * as this function always searchs for the head of the list with - * ucx_list_first(). - * - * @param list the list where to insert the data or NULL to create - * a new list - * @param data the data to insert - * @return a pointer to the new list head - */ -UcxList *ucx_list_prepend(UcxList *list, void *data); - -/** - * Inserts an element at the beginning of the list using a UcxAllocator. - * - * See ucx_list_prepend() for details. - * - * @param allocator the allocator to use - * @param list the list where to insert the data or NULL to create - * a new list - * @param data the data to insert - * @return a pointer to the new list head - * @see ucx_list_prepend() - */ -UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); - -/** - * Concatenates two lists. - * - * Either of the two arguments may be NULL. - * - * This function modifies the references to the next/previous element of - * the last/first element of list1/ - * list2. - * - * @param list1 first list - * @param list2 second list - * @return if list1 is NULL, list2 is - * returned, otherwise list1 is returned - */ -UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); - -/** - * Returns the first element of a list. - * - * If the argument is the list pointer, it is directly returned. Otherwise - * this function traverses to the first element of the list and returns the - * list pointer. - * - * @param elem one element of the list - * @return the first element of the list, the specified element is a member of - */ -UcxList *ucx_list_first(const UcxList *elem); - -/** - * Returns the last element of a list. - * - * If the argument has no successor, it is the last element and therefore - * directly returned. Otherwise this function traverses to the last element of - * the list and returns it. - * - * @param elem one element of the list - * @return the last element of the list, the specified element is a member of - */ -UcxList *ucx_list_last(const UcxList *elem); - -/** - * Returns the list element at the specified index. - * - * @param list the list to retrieve the element from - * @param index index of the element to return - * @return the element at the specified index or NULL, if the - * index is greater than the list size - */ -UcxList *ucx_list_get(const UcxList *list, size_t index); - -/** - * Returns the index of an element. - * - * @param list the list where to search for the element - * @param elem the element to find - * @return the index of the element or -1 if the list does not contain the - * element - */ -ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); - -/** - * Returns the element count of the list. - * - * @param list the list whose elements are counted - * @return the element count - */ -size_t ucx_list_size(const UcxList *list); - -/** - * Returns the index of an element containing the specified data. - * - * This function uses a cmp_func() to compare the data of each list element - * with the specified data. If no cmp_func is provided, the pointers are - * compared. - * - * If the list contains the data more than once, the index of the first - * occurrence is returned. - * - * @param list the list where to search for the data - * @param elem the element data - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return the index of the element containing the specified data or -1 if the - * data is not found in this list - */ -ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); - -/** - * Checks, if a list contains a specific element. - * - * An element is found, if ucx_list_find() returns a value greater than -1. - * - * @param list the list where to search for the data - * @param elem the element data - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return 1, if and only if the list contains the specified element data - * @see ucx_list_find() - */ -int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); - -/** - * Sorts a UcxList with natural merge sort. - * - * This function uses O(n) additional temporary memory for merge operations - * that is automatically freed after each merge. - * - * As the head of the list might change, you MUST call this function - * as follows: mylist = ucx_list_sort(mylist, mycmpfnc, mydata);. - * - * @param list the list to sort - * @param cmpfnc the function that shall be used to compare the element data - * @param data additional data for the cmp_func() - * @return the sorted list - */ -UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); - -/** - * Removes an element from the list. - * - * If the first element is removed, the list pointer changes. So it is - * highly recommended to always update the pointer by calling - * mylist = ucx_list_remove(mylist, myelem);. - * - * @param list the list from which the element shall be removed - * @param element the element to remove - * @return returns the updated list pointer or NULL, if the list - * is now empty - */ -UcxList *ucx_list_remove(UcxList *list, UcxList *element); - -/** - * Removes an element from the list using a UcxAllocator. - * - * See ucx_list_remove() for details. - * - * @param allocator the allocator to use - * @param list the list from which the element shall be removed - * @param element the element to remove - * @return returns the updated list pointer or NULL, if the list - * @see ucx_list_remove() - */ -UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, - UcxList *element); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_LIST_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/logging.c --- a/src/ucx/logging.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/logging.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,7 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "logging.h" +#include "ucx/logging.h" + #include #include #include @@ -49,6 +50,8 @@ ucx_map_int_put(logger->levels, l, (void*) "[WARNING]"); l = UCX_LOGGER_INFO; ucx_map_int_put(logger->levels, l, (void*) "[INFO]"); + l = UCX_LOGGER_DEBUG; + ucx_map_int_put(logger->levels, l, (void*) "[DEBUG]"); l = UCX_LOGGER_TRACE; ucx_map_int_put(logger->levels, l, (void*) "[TRACE]"); } @@ -68,12 +71,15 @@ const unsigned int line, const char *format, ...) { if (level <= logger->level) { char msg[UCX_LOGGER_MSGMAX]; - char *text; + const char *text; size_t k = 0; size_t n; if ((logger->mask & UCX_LOGGER_LEVEL) > 0) { - text = (char*) ucx_map_int_get(logger->levels, level); + text = (const char*) ucx_map_int_get(logger->levels, level); + if (!text) { + text = "[UNKNOWN]"; + } n = strlen(text); n = n > 256 ? 256 : n; memcpy(msg+k, text, n); @@ -91,7 +97,9 @@ k += sprintf(msg+k, ":%u ", line); } - msg[k++] = '-'; msg[k++] = ' '; + if (k > 0) { + msg[k++] = '-'; msg[k++] = ' '; + } va_list args; va_start (args, format); diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/logging.h --- a/src/ucx/logging.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Logging API. - * - * @file logging.h - * @author Mike Becker, Olaf Wintermann - */ -#ifndef UCX_LOGGING_H -#define UCX_LOGGING_H - -#include "ucx.h" -#include "map.h" -#include "string.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* leave enough space for custom log levels */ - -/** Log level for error messages. */ -#define UCX_LOGGER_ERROR 0x00 - -/** Log level for warning messages. */ -#define UCX_LOGGER_WARN 0x10 - -/** Log level for information messages. */ -#define UCX_LOGGER_INFO 0x20 - -/** Log level for debug messages. */ -#define UCX_LOGGER_DEBUG 0x30 - -/** Log level for trace messages. */ -#define UCX_LOGGER_TRACE 0x40 - -/** - * Output flag for the log level. - * If this flag is set, the log message will contain the log level. - * @see UcxLogger.mask - */ -#define UCX_LOGGER_LEVEL 0x01 - -/** - * Output flag for the timestmap. - * If this flag is set, the log message will contain the timestmap. - * @see UcxLogger.mask - */ -#define UCX_LOGGER_TIMESTAMP 0x02 - -/** - * Output flag for the source. - * If this flag is set, the log message will contain the source file and line - * number. - * @see UcxLogger.mask - */ -#define UCX_LOGGER_SOURCE 0x04 - -/** - * The UCX Logger object. - */ -typedef struct { - /** The stream this logger writes its messages to.*/ - void *stream; - - /** - * The write function that shall be used. - * For standard file or stdout loggers this might be standard fwrite - * (default). - */ - write_func writer; - - /** - * The date format for timestamp outputs including the delimiter - * (default: "%F %T %z "). - * @see UCX_LOGGER_TIMESTAMP - */ - char *dateformat; - - /** - * The level, this logger operates on. - * If a log command is issued, the message will only be logged, if the log - * level of the message is less or equal than the log level of the logger. - */ - unsigned int level; - - /** - * A configuration mask for automatic output. - * For each flag that is set, the logger automatically outputs some extra - * information like the timestamp or the source file and line number. - * See the documentation for the flags for details. - */ - unsigned int mask; - - /** - * A map of valid log levels for this logger. - * - * The keys represent all valid log levels and the values provide string - * representations, that are used, if the UCX_LOGGER_LEVEL flag is set. - * - * The exact data types are unsigned int for the key and - * const char* for the value. - * - * @see UCX_LOGGER_LEVEL - */ - UcxMap* levels; -} UcxLogger; - -/** - * Creates a new logger. - * @param stream the stream, which the logger shall write to - * @param level the level on which the logger shall operate - * @param mask configuration mask (cf. UcxLogger.mask) - * @return a new logger object - */ -UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask); - -/** - * Destroys the logger. - * - * The map containing the valid log levels is also automatically destroyed. - * - * @param logger the logger to destroy - */ -void ucx_logger_free(UcxLogger* logger); - -/** - * Internal log function - use macros instead. - * - * This function uses the format and variadic arguments for a - * printf()-style output of the log message. - * - * Dependent on the UcxLogger.mask some information is prepended. The complete - * format is: - * - * [LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message - * - * 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. - * - * @param logger the logger to use - * @param level the level to log on - * @param file information about the source file - * @param line information about the source line number - * @param format format string - * @param ... arguments - * @see ucx_logger_log() - */ -void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, - const unsigned int line, const char* format, ...); - -/** - * Logs a message at the specified level. - * @param logger the logger to use - * @param level the level to log the message on - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_log(logger, level, ...) \ - ucx_logger_logf(logger, level, __FILE__, __LINE__, __VA_ARGS__) - -/** - * Shortcut for logging an error message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_error(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_ERROR, __VA_ARGS__) - -/** - * Shortcut for logging an information message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_info(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_INFO, __VA_ARGS__) - -/** - * Shortcut for logging a warning message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_warn(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_WARN, __VA_ARGS__) - -/** - * Shortcut for logging a debug message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_debug(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_DEBUG, __VA_ARGS__) - -/** - * Shortcut for logging a trace message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_trace(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_TRACE, __VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_LOGGING_H */ diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/map.c --- a/src/ucx/map.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/map.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,11 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "ucx/map.h" + #include #include -#include "map.h" - UcxMap *ucx_map_new(size_t size) { return ucx_map_new_a(NULL, size); } @@ -86,7 +86,11 @@ UcxMapIterator iter = ucx_map_iterator(map); void *val; UCX_MAP_FOREACH(key, val, iter) { - destr(val); + if (destr) { + destr(val); + } else { + alfree(map->allocator, val); + } } } @@ -99,8 +103,7 @@ map->count = 0; } -int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, - copy_func fnc, void *data) { +int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data) { UcxMapIterator i = ucx_map_iterator(from); void *value; UCX_MAP_FOREACH(key, value, i) { @@ -151,19 +154,22 @@ UcxAllocator *allocator = map->allocator; if (key.hash == 0) { - key.hash = ucx_hash((char*)key.data, key.len); + key.hash = ucx_hash((const char*)key.data, key.len); } + + struct UcxMapKey mapkey; + mapkey.hash = key.hash; - size_t slot = key.hash%map->size; - UcxMapElement *restrict elm = map->map[slot]; - UcxMapElement *restrict prev = NULL; + size_t slot = mapkey.hash%map->size; + UcxMapElement *elm = map->map[slot]; + UcxMapElement *prev = NULL; - while (elm && elm->key.hash < key.hash) { + while (elm && elm->key.hash < mapkey.hash) { prev = elm; elm = elm->next; } - if (!elm || elm->key.hash != key.hash) { + if (!elm || elm->key.hash != mapkey.hash) { UcxMapElement *e = (UcxMapElement*)almalloc( allocator, sizeof(UcxMapElement)); if (!e) { @@ -185,8 +191,9 @@ return -1; } memcpy(kd, key.data, key.len); - key.data = kd; - elm->key = key; + mapkey.data = kd; + mapkey.len = key.len; + elm->key = mapkey; map->count++; } elm->data = data; @@ -194,14 +201,14 @@ return 0; } -void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) { +static void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, int remove) { if(key.hash == 0) { - key.hash = ucx_hash((char*)key.data, key.len); + key.hash = ucx_hash((const char*)key.data, key.len); } size_t slot = key.hash%map->size; - UcxMapElement *restrict elm = map->map[slot]; - UcxMapElement *restrict pelm = NULL; + UcxMapElement *elm = map->map[slot]; + UcxMapElement *pelm = NULL; while (elm && elm->key.hash <= key.hash) { if(elm->key.hash == key.hash) { int n = (key.len > elm->key.len) ? elm->key.len : key.len; @@ -236,11 +243,11 @@ return ucx_map_get_and_remove(map, key, 1); } -UcxKey ucx_key(void *data, size_t len) { +UcxKey ucx_key(const void *data, size_t len) { UcxKey key; key.data = data; key.len = len; - key.hash = ucx_hash((const char*) data, len); + key.hash = ucx_hash((const char*)data, len); return key; } @@ -309,7 +316,9 @@ if (e->data) { i->cur = e; *elm = e->data; - *key = e->key; + key->data = e->key.data; + key->hash = e->key.hash; + key->len = e->key.len; return 1; } diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/map.h --- a/src/ucx/map.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,423 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file map.h - * - * Hash map implementation. - * - * This implementation uses murmur hash 2 and separate chaining with linked - * lists. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_MAP_H -#define UCX_MAP_H - -#include "ucx.h" -#include "string.h" -#include "allocator.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Loop statement for UCX maps. - * - * The key variable is implicitly defined, but the - * value variable must be already declared as type information - * cannot be inferred. - * - * @param key the variable name for the key - * @param value the variable name for the value - * @param iter a UcxMapIterator - * @see ucx_map_iterator() - */ -#define UCX_MAP_FOREACH(key,value,iter) \ - for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&value);) - -/** Type for the UCX map. @see UcxMap */ -typedef struct UcxMap UcxMap; - -/** Type for a key of a UcxMap. @see UcxKey */ -typedef struct UcxKey UcxKey; - -/** Type for an element of a UcxMap. @see UcxMapElement */ -typedef struct UcxMapElement UcxMapElement; - -/** Type for an iterator over a UcxMap. @see UcxMapIterator */ -typedef struct UcxMapIterator UcxMapIterator; - -/** Structure for the UCX map. */ -struct UcxMap { - /** An allocator that is used for the map elements. */ - UcxAllocator *allocator; - /** The array of map element lists. */ - UcxMapElement **map; - /** The size of the map is the length of the element list array. */ - size_t size; - /** The count of elements currently stored in this map. */ - size_t count; -}; - -/** Structure for a key of a UcxMap. */ -struct UcxKey { - /** The key data. */ - void *data; - /** The length of the key data. */ - size_t len; - /** The hash value of the key data. */ - int hash; -}; - -/** Structure for an element of a UcxMap. */ -struct UcxMapElement { - /** The value data. */ - void *data; - - /** A pointer to the next element in the current list. */ - UcxMapElement *next; - - /** The corresponding key. */ - UcxKey key; -}; - -/** Structure for an iterator over a UcxMap. */ -struct UcxMapIterator { - /** The map to iterate over. */ - UcxMap *map; - - /** The current map element. */ - UcxMapElement *cur; - - /** - * The current index of the element list array. - * Attention: this is NOT the element index! Do NOT - * manually iterate over the map by increasing this index. Use - * ucx_map_iter_next(). - * @see UcxMap.map*/ - size_t index; -}; - -/** - * Creates a new hash map with the specified size. - * @param size the size of the hash map - * @return a pointer to the new hash map - */ -UcxMap *ucx_map_new(size_t size); - -/** - * Creates a new hash map with the specified size using a UcxAllocator. - * @param allocator the allocator to use - * @param size the size of the hash map - * @return a pointer to the new hash map - */ -UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size); - -/** - * Frees a hash map. - * - * Note: the contents are not freed, use ucx_map_free_content() - * before calling this function to achieve that. - * - * @param map the map to be freed - * @see ucx_map_free_content() - */ -void ucx_map_free(UcxMap *map); - -/** - * Frees the contents of a hash map. - * - * This is a convenience function that iterates over the map and passes all - * values to the specified destructor function (e.g. stdlib free()). - * - * You must ensure, that it is valid to pass each value in the map to the same - * destructor function. - * - * You should free or clear the map afterwards, as the contents will be invalid. - * - * @param map for which the contents shall be freed - * @param destr pointer to the destructor function - * @see ucx_map_free() - * @see ucx_map_clear() - */ -void ucx_map_free_content(UcxMap *map, ucx_destructor destr); - -/** - * Clears a hash map. - * - * Note: the contents are not freed, use ucx_map_free_content() - * before calling this function to achieve that. - * - * @param map the map to be cleared - * @see ucx_map_free_content() - */ -void ucx_map_clear(UcxMap *map); - - -/** - * Copies contents from a map to another map using a copy function. - * - * Note: The destination map does not need to be empty. However, if it - * contains data with keys that are also present in the source map, the contents - * are overwritten. - * - * @param from the source map - * @param to the destination map - * @param fnc the copy function or NULL if the pointer address - * shall be copied - * @param data additional data for the copy function - * @return 0 on success or a non-zero value on memory allocation errors - */ -int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, - copy_func fnc, void *data); - -/** - * Clones the map and rehashes if necessary. - * - * 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 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(UcxMap *map, copy_func fnc, void *data); - -/** - * Increases size of the hash map, if necessary. - * - * The load value is 0.75*UcxMap.size. If the element count exceeds the load - * value, the map needs to be rehashed. Otherwise no action is performed and - * this function simply returns 0. - * - * The rehashing process ensures, that the UcxMap.size is at least - * 2.5*UcxMap.count. So there is enough room for additional elements without - * the need of another soon rehashing. - * - * You can use this function to dramatically increase access performance. - * - * @param map the map to rehash - * @return 1, if a memory allocation error occurred, 0 otherwise - */ -int ucx_map_rehash(UcxMap *map); - -/** - * Puts a key/value-pair into the map. - * - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - */ -int ucx_map_put(UcxMap *map, UcxKey key, void *value); - -/** - * Retrieves a value by using a key. - * - * @param map the map - * @param key the key - * @return the value - */ -void* ucx_map_get(UcxMap *map, UcxKey key); - -/** - * Removes a key/value-pair from the map by using the key. - * - * @param map the map - * @param key the key - * @return the removed value - */ -void* ucx_map_remove(UcxMap *map, UcxKey key); - -/** - * Shorthand for putting data with a sstr_t key into the map. - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - * @see ucx_map_put() - */ -#define ucx_map_sstr_put(map, key, value) \ - ucx_map_put(map, ucx_key(key.ptr, key.length), (void*)value) - -/** - * Shorthand for putting data with a C string key into the map. - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - * @see ucx_map_put() - */ -#define ucx_map_cstr_put(map, key, value) \ - ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value) - -/** - * Shorthand for putting data with an integer key into the map. - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - * @see ucx_map_put() - */ -#define ucx_map_int_put(map, key, value) \ - ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value) - -/** - * Shorthand for getting data from the map with a sstr_t key. - * @param map the map - * @param key the key - * @return the value - * @see ucx_map_get() - */ -#define ucx_map_sstr_get(map, key) \ - ucx_map_get(map, ucx_key(key.ptr, key.length)) - -/** - * Shorthand for getting data from the map with a C string key. - * @param map the map - * @param key the key - * @return the value - * @see ucx_map_get() - */ -#define ucx_map_cstr_get(map, key) \ - ucx_map_get(map, ucx_key((void*)key, strlen(key))) - -/** - * Shorthand for getting data from the map with an integer key. - * @param map the map - * @param key the key - * @return the value - * @see ucx_map_get() - */ -#define ucx_map_int_get(map, key) \ - ucx_map_get(map, ucx_key((void*)&key, sizeof(int))) - -/** - * Shorthand for removing data from the map with a sstr_t key. - * @param map the map - * @param key the key - * @return the removed value - * @see ucx_map_remove() - */ -#define ucx_map_sstr_remove(map, key) \ - ucx_map_remove(map, ucx_key(key.ptr, key.length)) - -/** - * Shorthand for removing data from the map with a C string key. - * @param map the map - * @param key the key - * @return the removed value - * @see ucx_map_remove() - */ -#define ucx_map_cstr_remove(map, key) \ - ucx_map_remove(map, ucx_key((void*)key, strlen(key))) - -/** - * Shorthand for removing data from the map with an integer key. - * @param map the map - * @param key the key - * @return the removed value - * @see ucx_map_remove() - */ -#define ucx_map_int_remove(map, key) \ - ucx_map_remove(map, ucx_key((void*)&key, sizeof(key))) - -/** - * Creates a UcxKey based on the given data. - * - * This function implicitly computes the hash. - * - * @param data the data for the key - * @param len the length of the data - * @return a UcxKey with implicitly computed hash - * @see ucx_hash() - */ -UcxKey ucx_key(void *data, size_t len); - -/** - * Computes a murmur hash-2. - * - * @param data the data to hash - * @param len the length of the data - * @return the murmur hash-2 of the data - */ -int ucx_hash(const char *data, size_t len); - -/** - * Creates an iterator for a map. - * - * Note: A UcxMapIterator iterates over all elements in all element - * lists successively. Therefore the order highly depends on the key hashes and - * may vary under different map sizes. So generally you may NOT rely on - * the iteration order. - * - * Note: The iterator is NOT initialized. You need to call - * ucx_map_iter_next() at least once before accessing any information. However, - * it is not recommended to access the fields of a UcxMapIterator directly. - * - * @param map the map to create the iterator for - * @return an iterator initialized on the first element of the - * first element list - * @see ucx_map_iter_next() - */ -UcxMapIterator ucx_map_iterator(UcxMap *map); - -/** - * Proceeds to the next element of the map (if any). - * - * Subsequent calls on the same iterator proceed to the next element and - * store the key/value-pair into the memory specified as arguments of this - * function. - * - * If no further elements are found, this function returns zero and leaves the - * last found key/value-pair in memory. - * - * @param iterator the iterator to use - * @param key a pointer to the memory where to store the key - * @param value a pointer to the memory where to store the value - * @return 1, if another element was found, 0 if all elements has been processed - * @see ucx_map_iterator() - */ -int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value); - - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_MAP_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/mempool.c --- a/src/ucx/mempool.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/mempool.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,6 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "ucx/mempool.h" + #include #include #include @@ -34,8 +36,6 @@ #endif #include -#include "mempool.h" - /** Capsule for destructible memory chunks. */ typedef struct { /** The destructor for the memory chunk. */ @@ -56,18 +56,26 @@ void *ptr; } ucx_regdestr; -UCX_EXTERN void ucx_mempool_shared_destr(void* ptr) { +#ifdef __cplusplus +extern "C" +#endif +void ucx_mempool_shared_destr(void* ptr) { ucx_regdestr *rd = (ucx_regdestr*)ptr; rd->destructor(rd->ptr); } UcxMempool *ucx_mempool_new(size_t n) { + size_t poolsz; + if(ucx_szmul(n, sizeof(void*), &poolsz)) { + return NULL; + } + UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool)); if (!pool) { return NULL; } - pool->data = (void**) malloc(n * sizeof(void*)); + pool->data = (void**) malloc(poolsz); if (pool->data == NULL) { free(pool); return NULL; @@ -93,25 +101,39 @@ } int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) { - void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); + if (newcap < pool->ndata) { + return 1; + } + + size_t newcapsz; + if(ucx_szmul(newcap, sizeof(void*), &newcapsz)) { + return 1; + } + + void **data = (void**) realloc(pool->data, newcapsz); if (data) { pool->data = data; pool->size = newcap; - return EXIT_SUCCESS; + return 0; } else { - return EXIT_FAILURE; + return 1; } } void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { + if(((size_t)-1) - sizeof(ucx_destructor) < n) { + return NULL; + } + if (pool->ndata >= pool->size) { - // The hard coded 16 is documented for this function and ucx_mempool_new - if (ucx_mempool_chcap(pool, pool->size + 16) == EXIT_FAILURE) { + size_t newcap = pool->size*2; + if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) { return NULL; } } - ucx_memchunk *mem = (ucx_memchunk*)malloc(sizeof(ucx_destructor) + n); + void *p = malloc(sizeof(ucx_destructor) + n); + ucx_memchunk *mem = (ucx_memchunk*)p; if (!mem) { return NULL; } @@ -124,7 +146,12 @@ } void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) { - void *ptr = ucx_mempool_malloc(pool, nelem*elsize); + size_t msz; + if(ucx_szmul(nelem, elsize, &msz)) { + return NULL; + } + + void *ptr = ucx_mempool_malloc(pool, msz); if (!ptr) { return NULL; } @@ -133,6 +160,10 @@ } void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) { + if(((size_t)-1) - sizeof(ucx_destructor) < n) { + return NULL; + } + char *mem = ((char*)ptr) - sizeof(ucx_destructor); char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor)); if (!newm) { @@ -147,7 +178,7 @@ } fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", (intptr_t)ptr, (intptr_t)pool); - exit(EXIT_FAILURE); + abort(); } else { return newm + sizeof(ucx_destructor); } @@ -172,7 +203,7 @@ } fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", (intptr_t)ptr, (intptr_t)pool); - exit(EXIT_FAILURE); + abort(); } void ucx_mempool_destroy(UcxMempool *pool) { diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/mempool.h --- a/src/ucx/mempool.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file mempool.h - * - * Memory pool implementation. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_MEMPOOL_H -#define UCX_MEMPOOL_H - -#include "ucx.h" -#include -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * UCX mempool structure. - */ -typedef struct { - /** UcxAllocator based on this pool */ - UcxAllocator *allocator; - - /** List of pointers to pooled memory. */ - void **data; - - /** Count of pooled memory items. */ - size_t ndata; - - /** Memory pool size. */ - size_t size; -} UcxMempool; - -/** Shorthand for a new default memory pool with a capacity of 16 elements. */ -#define ucx_mempool_new_default() ucx_mempool_new(16) - - -/** - * Creates a memory pool with the specified initial size. - * - * As the created memory pool automatically grows in size by 16 elements, when - * trying to allocate memory on a full pool, it is recommended that you use - * a multiple of 16 for the initial size. - * - * @param n initial pool size (should be a multiple of 16) - * @return a pointer to the new memory pool - */ -UcxMempool *ucx_mempool_new(size_t n); - -/** - * Resizes a memory pool. - * - * @param pool the pool to resize - * @param newcap the new capacity - * @return EXIT_SUCCESS on success or - * EXIT_FAILURE on failure - */ -int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); - -/** - * Changes the pool size to the next smallest multiple of 16. - * - * You may use this macro, to reduce the pool size after freeing - * many pooled memory items. - * - * @param pool the pool to clamp - * @return EXIT_SUCCESS on success or - * EXIT_FAILURE on failure - */ -#define ucx_mempool_clamp(pool) ucx_mempool_chcap(pool, \ - (pool->ndata & ~0xF)+0x10) - -/** - * Allocates pooled memory. - * - * @param pool the memory pool - * @param n amount of memory to allocate - * @return a pointer to the allocated memory - * @see ucx_allocator_malloc() - */ -void *ucx_mempool_malloc(UcxMempool *pool, size_t n); -/** - * Allocates a pooled memory array. - * - * The content of the allocated memory is set to zero. - * - * @param pool the memory pool - * @param nelem amount of elements to allocate - * @param elsize amount of memory per element - * @return a pointer to the allocated memory - * @see ucx_allocator_calloc() - */ -void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize); - -/** - * Reallocates pooled memory. - * - * If the memory to be reallocated is not contained by the specified pool, the - * behavior is undefined. - * - * @param pool the memory pool - * @param ptr a pointer to the memory that shall be reallocated - * @param n the new size of the memory - * @return a pointer to the new location of the memory - * @see ucx_allocator_realloc() - */ -void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); - -/** - * Frees pooled memory. - * - * Before freeing the memory, the specified destructor function (if any) - * is called. - * - * If you specify memory, that is not pooled by the specified memory pool, the - * behavior is undefined. - * - * @param pool the memory pool - * @param ptr a pointer to the memory that shall be freed - * @see ucx_mempool_set_destr() - */ -void ucx_mempool_free(UcxMempool *pool, void *ptr); - -/** - * Destroys a memory pool. - * - * For each element the destructor function (if any) is called and the element - * is freed. - * - * Each of the registered destructor function that has no corresponding element - * within the pool (namely those registered by ucx_mempool_reg_destr) is - * called interleaving with the element destruction, but with guarantee to the - * order in which they were registered (FIFO order). - * - * - * @param pool the mempool to destroy - */ -void ucx_mempool_destroy(UcxMempool *pool); - -/** - * Sets a destructor function for the specified memory. - * - * The destructor is automatically called when the memory is freed or the - * pool is destroyed. - * - * The only requirement for the specified memory is, that it MUST be - * pooled memory by a UcxMempool or an element-compatible mempool. The pointer - * to the destructor function is saved in a reserved area before the actual - * memory. - * - * @param ptr pooled memory - * @param func a pointer to the destructor function - * @see ucx_mempool_free() - * @see ucx_mempool_destroy() - */ -void ucx_mempool_set_destr(void *ptr, ucx_destructor func); - -/** - * Registers a destructor function for the specified (non-pooled) memory. - * - * This is useful, if you have memory that has not been allocated by a mempool, - * but shall be managed by a mempool. - * - * This function creates an entry in the specified mempool and the memory will - * therefore (logically) convert to pooled memory. - * - * @param pool the memory pool - * @param ptr data the destructor is registered for - * @param destr a pointer to the destructor function - */ -void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_MEMPOOL_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/properties.c --- a/src/ucx/properties.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/properties.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,12 +26,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "ucx/properties.h" + #include #include #include -#include "properties.h" - UcxProperties *ucx_properties_new() { UcxProperties *parser = (UcxProperties*)malloc( sizeof(UcxProperties)); diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/properties.h --- a/src/ucx/properties.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * @file properties.h - * - * Load / store utilities for properties files. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_PROPERTIES_H -#define UCX_PROPERTIES_H - -#include "ucx.h" -#include "map.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * UcxProperties object for parsing properties data. - * Most of the fields are for internal use only. You may configure the - * properties parser, e.g. by changing the used delimiter or specifying - * up to three different characters that shall introduce comments. - */ -typedef struct { - /** - * Input buffer (don't set manually). - * Automatically set by calls to ucx_properties_fill(). - */ - char *buffer; - - /** - * Length of the input buffer (don't set manually). - * Automatically set by calls to ucx_properties_fill(). - */ - size_t buflen; - - /** - * Current buffer position (don't set manually). - * Used by ucx_properties_next(). - */ - size_t pos; - - /** - * Internal temporary buffer (don't set manually). - * Used by ucx_properties_next(). - */ - char *tmp; - - /** - * Internal temporary buffer length (don't set manually). - * Used by ucx_properties_next(). - */ - size_t tmplen; - - /** - * Internal temporary buffer capacity (don't set manually). - * Used by ucx_properties_next(). - */ - size_t tmpcap; - - /** - * Parser error code. - * This is always 0 on success and a nonzero value on syntax errors. - * The value is set by ucx_properties_next(). - */ - int error; - - /** - * The delimiter that shall be used. - * This is '=' by default. - */ - char delimiter; - - /** - * The first comment character. - * This is '#' by default. - */ - char comment1; - - /** - * The second comment character. - * This is not set by default. - */ - char comment2; - - /** - * The third comment character. - * This is not set by default. - */ - char comment3; -} UcxProperties; - - -/** - * Constructs a new UcxProperties object. - * @return a pointer to the new UcxProperties object - */ -UcxProperties *ucx_properties_new(); - -/** - * Destroys a UcxProperties object. - * @param prop the UcxProperties object to destroy - */ -void ucx_properties_free(UcxProperties *prop); - -/** - * Sets the input buffer for the properties parser. - * - * After calling this function, you may parse the data by calling - * ucx_properties_next() until it returns 0. The function ucx_properties2map() - * is a convenience function that reads as much data as possible by using this - * function. - * - * - * @param prop the UcxProperties object - * @param buf a pointer to the new buffer - * @param len the payload length of the buffer - * @see ucx_properties_next() - * @see ucx_properties2map() - */ -void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len); - -/** - * Retrieves the next key/value-pair. - * - * This function returns a nonzero value as long as there are key/value-pairs - * found. If no more key/value-pairs are found, you may refill the input buffer - * with ucx_properties_fill(). - * - * Attention: the sstr_t.ptr pointers of the output parameters point to - * memory within the input buffer of the parser and will get invalid some time. - * If you want long term copies of the key/value-pairs, use sstrdup() after - * calling this function. - * - * @param prop the UcxProperties object - * @param name a pointer to the sstr_t that shall contain the property name - * @param value a pointer to the sstr_t that shall contain the property value - * @return Nonzero, if a key/value-pair was successfully retrieved - * @see ucx_properties_fill() - */ -int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value); - -/** - * Retrieves all available key/value-pairs and puts them into a UcxMap. - * - * This is done by successive calls to ucx_properties_next() until no more - * key/value-pairs can be retrieved. - * - * @param prop the UcxProperties object - * @param map the target map - * @return The UcxProperties.error code (i.e. 0 on success). - * @see ucx_properties_fill() - */ -int ucx_properties2map(UcxProperties *prop, UcxMap *map); - -/** - * Loads a properties file to a UcxMap. - * - * This is a convenience function that reads data from an input - * stream until the end of the stream is reached. - * - * @param map the map object to write the key/value-pairs to - * @param file the FILE* stream to read from - * @return 0 on success, or a non-zero value on error - * - * @see ucx_properties_fill() - * @see ucx_properties2map() - */ -int ucx_properties_load(UcxMap *map, FILE *file); - -/** - * Stores a UcxMap to a file. - * - * The key/value-pairs are written by using the following format: - * - * [key] = [value]\\n - * - * @param map the map to store - * @param file the FILE* stream to write to - * @return 0 on success, or a non-zero value on error - */ -int ucx_properties_store(UcxMap *map, FILE *file); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_PROPERTIES_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/stack.c --- a/src/ucx/stack.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/stack.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,7 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "stack.h" +#include "ucx/stack.h" + #include static size_t ucx_stack_align(size_t n) { @@ -119,13 +120,15 @@ return; } - size_t len = ucx_stack_topsize(stack); - if (len > n) { - len = n; + if (dest) { + size_t len = ucx_stack_topsize(stack); + if (len > n) { + len = n; + } + + memcpy(dest, stack->top, len); } - memcpy(dest, stack->top, len); - ucx_stack_free(stack, stack->top); } @@ -141,3 +144,22 @@ return 0; } } + +void *ucx_stack_push(UcxStack *stack, size_t n, const void *data) { + void *space = ucx_stack_malloc(stack, n); + if (space) { + memcpy(space, data, n); + } + return space; +} + +void *ucx_stack_pusharr(UcxStack *stack, + size_t nelem, size_t elsize, const void *data) { + + // skip the memset by using malloc + void *space = ucx_stack_malloc(stack, nelem*elsize); + if (space) { + memcpy(space, data, nelem*elsize); + } + return space; +} diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/stack.h --- a/src/ucx/stack.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file stack.h - * - * Default stack memory allocation implementation. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_STACK_H -#define UCX_STACK_H - -#include "ucx.h" -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * UCX stack structure. - */ -typedef struct { - /** UcxAllocator based on this stack */ - UcxAllocator allocator; - - /** Stack size. */ - size_t size; - - /** Pointer to the bottom of the stack */ - char *space; - - /** Pointer to the top of the stack */ - char *top; -} UcxStack; - -/** - * Metadata for each UCX stack element. - */ -struct ucx_stack_metadata { - /** - * Location of the previous element (NULL if this is the first) - */ - char *prev; - - /** Size of this element */ - size_t size; -}; - -/** - * Initializes UcxStack structure with memory. - * - * @param stack a pointer to an uninitialized stack structure - * @param space the memory area that shall be managed - * @param size size of the memory area - * @return a new UcxStack structure - */ -void ucx_stack_init(UcxStack *stack, char* space, size_t size); - -/** - * Allocates stack memory. - * - * @param stack a pointer to the stack - * @param n amount of memory to allocate - * @return a pointer to the allocated memory - * @see ucx_allocator_malloc() - */ -void *ucx_stack_malloc(UcxStack *stack, size_t n); - -/** - * Alias for #ucx_stack_malloc(). - * @param stack a pointer to the stack - * @param n amount of memory to allocate - * @return a pointer to the allocated memory - * @see ucx_stack_malloc - */ -#define ucx_stack_push(stack, n) ucx_stack_malloc(stack, n) - -/** - * Allocates an array of stack memory - * - * The content of the allocated memory is set to zero. - * - * @param stack a pointer to the stack - * @param nelem amount of elements to allocate - * @param elsize amount of memory per element - * @return a pointer to the allocated memory - * @see ucx_allocator_calloc() - */ -void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize); - -/** - * Alias for #ucx_stack_calloc(). - * - * @param stack a pointer to the stack - * @param n amount of elements to allocate - * @param elsize amount of memory per element - * @return a pointer to the allocated memory - * @see ucx_stack_calloc - */ -#define ucx_stack_pusharr(stack,n,elsize) ucx_stack_calloc(stack,n,elssize) - -/** - * Reallocates memory on the stack. - * - * Shrinking memory is always safe. Extending memory can be very expensive. - * - * @param stack the stack - * @param ptr a pointer to the memory that shall be reallocated - * @param n the new size of the memory - * @return a pointer to the new location of the memory - * @see ucx_allocator_realloc() - */ -void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n); - -/** - * Frees memory on the stack. - * - * Freeing stack memory behaves in a special way. - * - * If the element, that should be freed, is the top most element of the stack, - * it is removed from the stack. Otherwise it is marked as freed. Marked - * elements are removed, when they become the top most elements of the stack. - * - * @param stack a pointer to the stack - * @param ptr a pointer to the memory that shall be freed - */ -void ucx_stack_free(UcxStack *stack, void *ptr); - - -/** - * Returns the size of the top most element. - * @param stack a pointer to the stack - * @return the size of the top most element - */ -#define ucx_stack_topsize(stack) ((stack)->top ? ((struct ucx_stack_metadata*)\ - (stack)->top - 1)->size : 0) - -/** - * Removes the top most element from the stack and copies the content to - * dest, if specified. - * - * Use #ucx_stack_topsize()# to get the amount of memory that must be available - * at the location of dest. - * - * @param stack a pointer to the stack - * @param dest the location where the contents shall be written to, or - * NULL, if the element shall only be removed. - * @see ucx_stack_free - * @see ucx_stack_popn - */ -#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, (size_t)-1) - -/** - * Removes the top most element from the stack and copies the content to - * dest. - * - * In contrast to #ucx_stack_pop() the dest pointer MUST - * NOT be NULL. - * - * @param stack a pointer to the stack - * @param dest the location where the contents shall be written to - * @param n copies at most n elements to dest - * @see ucx_stack_pop - */ -void ucx_stack_popn(UcxStack *stack, void *dest, size_t n); - -/** - * Returns the remaining available memory on the specified stack. - * - * @param stack a pointer to the stack - * @return the remaining available memory - */ -size_t ucx_stack_avail(UcxStack *stack); - -/** - * Checks, if the stack is empty. - * - * @param stack a pointer to the stack - * @return nonzero, if the stack is empty, zero otherwise - */ -#define ucx_stack_empty(stack) (!(stack)->top) - -/** - * Computes a recommended size for the stack memory area. Note, that - * reallocations have not been taken into account, so you might need to reserve - * twice as much memory to allow many reallocations. - * - * @param size the approximate payload - * @param elems the approximate count of element allocations - * @return a recommended size for the stack space based on the information - * provided - */ -#define ucx_stack_dim(size, elems) (size+sizeof(struct ucx_stack_metadata) * \ - (elems + 1)) - - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_STACK_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/string.c --- a/src/ucx/string.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/string.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,13 +26,19 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "ucx/string.h" + +#include "ucx/allocator.h" + #include #include #include +#include #include -#include "string.h" -#include "allocator.h" +#ifndef _WIN32 +#include /* for strncasecmp() */ +#endif /* _WIN32 */ sstr_t sstr(char *cstring) { sstr_t string; @@ -48,13 +54,35 @@ return string; } -size_t sstrnlen(size_t n, sstr_t s, ...) { +scstr_t scstr(const char *cstring) { + scstr_t string; + string.ptr = cstring; + string.length = strlen(cstring); + return string; +} + +scstr_t scstrn(const char *cstring, size_t length) { + scstr_t string; + string.ptr = cstring; + string.length = length; + return string; +} + + +size_t scstrnlen(size_t n, ...) { + if (n == 0) return 0; + va_list ap; - size_t size = s.length; - va_start(ap, s); + va_start(ap, n); + + size_t size = 0; - for (size_t i = 1 ; i < n ; i++) { - sstr_t str = va_arg(ap, sstr_t); + for (size_t i = 0 ; i < n ; i++) { + scstr_t str = va_arg(ap, scstr_t); + if(SIZE_MAX - str.length < size) { + size = SIZE_MAX; + break; + } size += str.length; } va_end(ap); @@ -65,8 +93,7 @@ static sstr_t sstrvcat_a( UcxAllocator *a, size_t count, - sstr_t s1, - sstr_t s2, + scstr_t s1, va_list ap) { sstr_t str; str.ptr = NULL; @@ -75,7 +102,13 @@ return str; } - sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t)); + scstr_t s2 = va_arg (ap, scstr_t); + + if(((size_t)-1) - s1.length < s2.length) { + return str; + } + + scstr_t *strings = (scstr_t*) calloc(count, sizeof(scstr_t)); if(!strings) { return str; } @@ -83,16 +116,25 @@ // get all args and overall length strings[0] = s1; strings[1] = s2; - size_t strlen = s1.length + s2.length; + size_t slen = s1.length + s2.length; + int error = 0; for (size_t i=2;i str_length) { + return 0; + } + + if(length > str_length - start) { + length = str_length - start; + } + *newlen = length; + *newpos = start; + return 1; } sstr_t sstrsubs(sstr_t s, size_t start) { @@ -135,132 +199,301 @@ } sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) { - sstr_t new_sstr; - if (start >= s.length) { - new_sstr.ptr = NULL; - new_sstr.length = 0; - } else { - if (length > s.length-start) { - length = s.length-start; + size_t pos; + sstr_t ret = { NULL, 0 }; + if(ucx_substring(s.length, start, length, &ret.length, &pos)) { + ret.ptr = s.ptr + pos; + } + return ret; +} + +scstr_t scstrsubs(scstr_t string, size_t start) { + return scstrsubsl(string, start, string.length-start); +} + +scstr_t scstrsubsl(scstr_t s, size_t start, size_t length) { + size_t pos; + scstr_t ret = { NULL, 0 }; + if(ucx_substring(s.length, start, length, &ret.length, &pos)) { + ret.ptr = s.ptr + pos; + } + return ret; +} + + +static int ucx_strchr(const char *str, size_t length, int chr, size_t *pos) { + for(size_t i=0;i 0) { + for(size_t i=length ; i>0 ; i--) { + if(str[i-1] == chr) { + *pos = i-1; + return 1; + } + } + } + return 0; } sstr_t sstrchr(sstr_t s, int c) { - for(size_t i=0;i 0) { - for(size_t i=s.length;i>0;i--) { - if(s.ptr[i-1] == c) { - return sstrsubs(s, i-1); - } - } + size_t pos = 0; + if(ucx_strrchr(s.ptr, s.length, c, &pos)) { + return sstrsubs(s, pos); } - sstr_t n; - n.ptr = NULL; - n.length = 0; - return n; + return sstrn(NULL, 0); +} + +scstr_t scstrchr(scstr_t s, int c) { + size_t pos = 0; + if(ucx_strchr(s.ptr, s.length, c, &pos)) { + return scstrsubs(s, pos); + } + return scstrn(NULL, 0); } -sstr_t sstrstr(sstr_t string, sstr_t match) { - if (match.length == 0) { - return string; +scstr_t scstrrchr(scstr_t s, int c) { + size_t pos = 0; + if(ucx_strrchr(s.ptr, s.length, c, &pos)) { + return scstrsubs(s, pos); + } + return scstrn(NULL, 0); +} + +#define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \ + ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index]) + +#define ptable_w(useheap, ptable, index, src) do {\ + if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\ + else ((size_t*)ptable)[index] = src;\ + } while (0); + + +static const char* ucx_strstr( + const char *str, + size_t length, + const char *match, + size_t matchlen, + size_t *newlen) +{ + *newlen = length; + if (matchlen == 0) { + return str; } - for (size_t i = 0 ; i < string.length ; i++) { - sstr_t substr = sstrsubs(string, i); - if (sstrprefix(substr, match)) { - return substr; + const char *result = NULL; + size_t resultlen = 0; + + /* + * IMPORTANT: + * our prefix table contains the prefix length PLUS ONE + * this is our decision, because we want to use the full range of size_t + * the original algorithm needs a (-1) at one single place + * and we want to avoid that + */ + + /* static prefix table */ + static uint8_t s_prefix_table[256]; + + /* check pattern length and use appropriate prefix table */ + /* if the pattern exceeds static prefix table, allocate on the heap */ + register int useheap = matchlen > 255; + register void* ptable = useheap ? + calloc(matchlen+1, sizeof(size_t)): s_prefix_table; + + /* keep counter in registers */ + register size_t i, j; + + /* fill prefix table */ + i = 0; j = 0; + ptable_w(useheap, ptable, i, j); + while (i < matchlen) { + while (j >= 1 && match[j-1] != match[i]) { + ptable_r(j, useheap, ptable, j-1); } + i++; j++; + ptable_w(useheap, ptable, i, j); + } + + /* search */ + i = 0; j = 1; + while (i < length) { + while (j >= 1 && str[i] != match[j-1]) { + ptable_r(j, useheap, ptable, j-1); + } + i++; j++; + if (j-1 == matchlen) { + size_t start = i - matchlen; + result = str + start; + resultlen = length - start; + break; + } + } + + /* if prefix table was allocated on the heap, free it */ + if (ptable != s_prefix_table) { + free(ptable); } - sstr_t emptystr; - emptystr.length = 0; - emptystr.ptr = NULL; - return emptystr; + *newlen = resultlen; + return result; +} + +sstr_t scstrsstr(sstr_t string, scstr_t match) { + sstr_t result; + + size_t reslen; + const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen); + if(!resstr) { + result.ptr = NULL; + result.length = 0; + return result; + } + + size_t pos = resstr - string.ptr; + result.ptr = string.ptr + pos; + result.length = reslen; + + return result; } -sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { - return sstrsplit_a(ucx_default_allocator(), s, d, n); +scstr_t scstrscstr(scstr_t string, scstr_t match) { + scstr_t result; + + size_t reslen; + const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen); + if(!resstr) { + result.ptr = NULL; + result.length = 0; + return result; + } + + size_t pos = resstr - string.ptr; + result.ptr = string.ptr + pos; + result.length = reslen; + + return result; } -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) { +#undef ptable_r +#undef ptable_w + +sstr_t* scstrsplit(scstr_t s, scstr_t d, ssize_t *n) { + return scstrsplit_a(ucx_default_allocator(), s, d, n); +} + +sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t s, scstr_t d, ssize_t *n) { if (s.length == 0 || d.length == 0) { *n = -1; return NULL; } - - sstr_t* result; - ssize_t nmax = *n; - *n = 1; - - /* special case: exact match - no processing needed */ - if (sstrcmp(s, d) == 0) { - *n = 0; - return NULL; + + /* special cases: delimiter is at least as large as the string */ + if (d.length >= s.length) { + /* exact match */ + if (sstrcmp(s, d) == 0) { + *n = 0; + return NULL; + } else /* no match possible */ { + *n = 1; + sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)); + if(result) { + *result = sstrdup_a(allocator, s); + } else { + *n = -2; + } + return result; + } } - sstr_t sv = sstrdup(s); - if (sv.length == 0) { - *n = -2; - return NULL; - } - - for (size_t i = 0 ; i < s.length ; i++) { - sstr_t substr = sstrsubs(sv, i); - if (sstrprefix(substr, d)) { - (*n)++; - for (size_t j = 0 ; j < d.length ; j++) { - sv.ptr[i+j] = 0; - } - i += d.length - 1; // -1, because the loop will do a i++ - } - if ((*n) == nmax) break; - } - result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)*(*n)); + + ssize_t nmax = *n; + size_t arrlen = 16; + sstr_t* result = (sstr_t*) alcalloc(allocator, arrlen, sizeof(sstr_t)); if (result) { - char *pptr = sv.ptr; - for (ssize_t i = 0 ; i < *n ; i++) { - size_t l = strlen(pptr); - char* ptr = (char*) almalloc(allocator, l + 1); - if (ptr) { - memcpy(ptr, pptr, l); - ptr[l] = 0; + scstr_t curpos = s; + ssize_t j = 1; + while (1) { + scstr_t match; + /* optimize for one byte delimiters */ + if (d.length == 1) { + match = curpos; + for (size_t i = 0 ; i < curpos.length ; i++) { + if (curpos.ptr[i] == *(d.ptr)) { + match.ptr = curpos.ptr + i; + break; + } + match.length--; + } + } else { + match = scstrscstr(curpos, d); + } + if (match.length > 0) { + /* is this our last try? */ + if (nmax == 0 || j < nmax) { + /* copy the current string to the array */ + scstr_t item = scstrn(curpos.ptr, match.ptr - curpos.ptr); + result[j-1] = sstrdup_a(allocator, item); + size_t processed = item.length + d.length; + curpos.ptr += processed; + curpos.length -= processed; - result[i] = sstrn(ptr, l); - pptr += l + d.length; + /* allocate memory for the next string */ + j++; + if (j > arrlen) { + arrlen *= 2; + size_t reallocsz; + sstr_t* reallocated = NULL; + if(!ucx_szmul(arrlen, sizeof(sstr_t), &reallocsz)) { + reallocated = (sstr_t*) alrealloc( + allocator, result, reallocsz); + } + if (reallocated) { + result = reallocated; + } else { + for (ssize_t i = 0 ; i < j-1 ; i++) { + alfree(allocator, result[i].ptr); + } + alfree(allocator, result); + *n = -2; + return NULL; + } + } + } else { + /* nmax reached, copy the _full_ remaining string */ + result[j-1] = sstrdup_a(allocator, curpos); + break; + } } else { - for (ssize_t j = i-1 ; j >= 0 ; j--) { - alfree(allocator, result[j].ptr); - } - alfree(allocator, result); - *n = -2; + /* no more matches, copy last string */ + result[j-1] = sstrdup_a(allocator, curpos); break; } } + *n = j; } else { *n = -2; } - - free(sv.ptr); return result; } -int sstrcmp(sstr_t s1, sstr_t s2) { +int scstrcmp(scstr_t s1, scstr_t s2) { if (s1.length == s2.length) { return memcmp(s1.ptr, s2.ptr, s1.length); } else if (s1.length > s2.length) { @@ -270,7 +503,7 @@ } } -int sstrcasecmp(sstr_t s1, sstr_t s2) { +int scstrcasecmp(scstr_t s1, scstr_t s2) { if (s1.length == s2.length) { #ifdef _WIN32 return _strnicmp(s1.ptr, s2.ptr, s1.length); @@ -284,11 +517,11 @@ } } -sstr_t sstrdup(sstr_t s) { +sstr_t scstrdup(scstr_t s) { return sstrdup_a(ucx_default_allocator(), s); } -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { +sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t s) { sstr_t newstring; newstring.ptr = (char*)almalloc(allocator, s.length + 1); if (newstring.ptr) { @@ -303,21 +536,38 @@ return newstring; } -sstr_t sstrtrim(sstr_t string) { - sstr_t newstr = string; + +static size_t ucx_strtrim(const char *s, size_t len, size_t *newlen) { + const char *newptr = s; + size_t length = len; - while (newstr.length > 0 && isspace(*newstr.ptr)) { - newstr.ptr++; - newstr.length--; + while(length > 0 && isspace(*newptr)) { + newptr++; + length--; } - while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) { - newstr.length--; + while(length > 0 && isspace(newptr[length-1])) { + length--; } + *newlen = length; + return newptr - s; +} + +sstr_t sstrtrim(sstr_t string) { + sstr_t newstr; + newstr.ptr = string.ptr + + ucx_strtrim(string.ptr, string.length, &newstr.length); return newstr; } -int sstrprefix(sstr_t string, sstr_t prefix) { +scstr_t scstrtrim(scstr_t string) { + scstr_t newstr; + newstr.ptr = string.ptr + + ucx_strtrim(string.ptr, string.length, &newstr.length); + return newstr; +} + +int scstrprefix(scstr_t string, scstr_t prefix) { if (string.length == 0) { return prefix.length == 0; } @@ -332,7 +582,7 @@ } } -int sstrsuffix(sstr_t string, sstr_t suffix) { +int scstrsuffix(scstr_t string, scstr_t suffix) { if (string.length == 0) { return suffix.length == 0; } @@ -348,7 +598,39 @@ } } -sstr_t sstrlower(sstr_t string) { +int scstrcaseprefix(scstr_t string, scstr_t prefix) { + if (string.length == 0) { + return prefix.length == 0; + } + if (prefix.length == 0) { + return 1; + } + + if (prefix.length > string.length) { + return 0; + } else { + scstr_t subs = scstrsubsl(string, 0, prefix.length); + return scstrcasecmp(subs, prefix) == 0; + } +} + +int scstrcasesuffix(scstr_t string, scstr_t suffix) { + if (string.length == 0) { + return suffix.length == 0; + } + if (suffix.length == 0) { + return 1; + } + + if (suffix.length > string.length) { + return 0; + } else { + scstr_t subs = scstrsubs(string, string.length-suffix.length); + return scstrcasecmp(subs, suffix) == 0; + } +} + +sstr_t scstrlower(scstr_t string) { sstr_t ret = sstrdup(string); for (size_t i = 0; i < ret.length ; i++) { ret.ptr[i] = tolower(ret.ptr[i]); @@ -356,7 +638,7 @@ return ret; } -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) { +sstr_t scstrlower_a(UcxAllocator *allocator, scstr_t string) { sstr_t ret = sstrdup_a(allocator, string); for (size_t i = 0; i < ret.length ; i++) { ret.ptr[i] = tolower(ret.ptr[i]); @@ -364,7 +646,7 @@ return ret; } -sstr_t sstrupper(sstr_t string) { +sstr_t scstrupper(scstr_t string) { sstr_t ret = sstrdup(string); for (size_t i = 0; i < ret.length ; i++) { ret.ptr[i] = toupper(ret.ptr[i]); @@ -372,10 +654,24 @@ return ret; } -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) { +sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string) { sstr_t ret = sstrdup_a(allocator, string); for (size_t i = 0; i < ret.length ; i++) { ret.ptr[i] = toupper(ret.ptr[i]); } return ret; } + +// type adjustment functions +scstr_t ucx_sc2sc(scstr_t str) { + return str; +} +scstr_t ucx_ss2sc(sstr_t str) { + scstr_t cs; + cs.ptr = str.ptr; + cs.length = str.length; + return cs; +} +scstr_t ucx_ss2c_s(scstr_t c) { + return c; +} diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/string.h --- a/src/ucx/string.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,457 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Bounded string implementation. - * - * The UCX strings (sstr_t) provide an alternative to C strings. - * The main difference to C strings is, that sstr_t does not - * need to be NULL-terminated. Instead the length is stored - * within the structure. - * - * When using sstr_t, developers must be full aware of what type - * of string (NULL-terminated) or not) they are using, when - * accessing the char* ptr directly. - * - * The UCX string module provides some common string functions, known from - * standard libc, working with sstr_t. - * - * @file string.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_STRING_H -#define UCX_STRING_H - -#include "ucx.h" -#include "allocator.h" -#include - -/** Shortcut for a sstr_t struct literal. */ -#define ST(s) { (char*)s, sizeof(s)-1 } - -/** Shortcut for the conversion of a C string to a sstr_t. */ -#define S(s) sstrn((char*)s, sizeof(s)-1) - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The UCX string structure. - */ -typedef struct { - /** A reference to the string (not necessarily NULL - * -terminated) */ - char *ptr; - /** The length of the string */ - size_t length; -} sstr_t; - -/** - * Creates a new sstr_t based on a C string. - * - * The length is implicitly inferred by using a call to strlen(). - * - * Note: the sstr_t will hold a reference to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. - * - * @param cstring the C string to wrap - * @return a new sstr_t containing the C string - * - * @see sstrn() - */ -sstr_t sstr(char *cstring); - -/** - * Creates a new sstr_t of the specified length based on a C string. - * - * Note: the sstr_t will hold a reference to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. - * - * @param cstring the C string to wrap - * @param length the length of the string - * @return a new sstr_t containing the C string - * - * @see sstr() - * @see S() - */ -sstr_t sstrn(char *cstring, size_t length); - - -/** - * Returns the cumulated length of all specified strings. - * - * At least one string must be specified. - * - * Attention: if the count argument does not match the count of the - * specified strings, the behavior is undefined. - * - * @param count the total number of specified strings (so at least 1) - * @param string the first string - * @param ... all other strings - * @return the cumulated length of all strings - */ -size_t sstrnlen(size_t count, sstr_t string, ...); - -/** - * Concatenates two or more strings. - * - * The resulting string will be allocated by standard malloc(). - * So developers MUST pass the sstr_t.ptr to free(). - * - * The sstr_t.ptr of the return value will always be NULL- - * terminated. - * - * @param count the total number of strings to concatenate - * @param s1 first string - * @param s2 second string - * @param ... all remaining strings - * @return the concatenated string - */ -sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); - -/** - * Concatenates two or more strings using a UcxAllocator. - * - * See sstrcat() for details. - * - * @param a the allocator to use - * @param count the total number of strings to concatenate - * @param s1 first string - * @param s2 second string - * @param ... all remaining strings - * @return the concatenated string - */ -sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...); - - -/** - * Returns a substring starting at the specified location. - * - * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. - * Use sstrdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @return a substring of string starting at start - * - * @see sstrsubsl() - * @see sstrchr() - */ -sstr_t sstrsubs(sstr_t string, size_t start); - -/** - * Returns a substring with a maximum length starting at the specified location. - * - * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. - * Use sstrdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @param length the maximum length of the substring - * @return a substring of string starting at start - * with a maximum length of length - * - * @see sstrsubs() - * @see sstrchr() - */ -sstr_t sstrsubsl(sstr_t string, size_t start, size_t length); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of chr - * - * @see sstrsubs() - */ -sstr_t sstrchr(sstr_t string, int chr); - -/** - * Returns a substring starting at the location of the last occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of chr - * - * @see sstrsubs() - */ -sstr_t sstrrchr(sstr_t string, int chr); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified string. - * - * If the string does not contain the other string, an empty string is returned. - * - * If match is an empty string, the complete string is - * returned. - * - * @param string the string to be scanned - * @param match string containing the sequence of characters to match - * @return a substring starting at the first occurrence of - * match, or an empty string, if the sequence is not - * present in string - */ -sstr_t sstrstr(sstr_t string, sstr_t match); - -/** - * Splits a string into parts by using a delimiter string. - * - * This function will return NULL, if one of the following happens: - *
    - *
  • the string length is zero
  • - *
  • the delimeter length is zero
  • - *
  • the string equals the delimeter
  • - *
  • memory allocation fails
  • - *
- * - * The integer referenced by count is used as input and determines - * the maximum size of the resulting array, i.e. the maximum count of splits to - * perform + 1. - * - * The integer referenced by count is also used as output and is - * set to - *
    - *
  • -2, on memory allocation errors
  • - *
  • -1, if either the string or the delimiter is an empty string
  • - *
  • 0, if the string equals the delimiter
  • - *
  • 1, if the string does not contain the delimiter
  • - *
  • the count of array items, otherwise
  • - *
- * - * If the string starts with the delimiter, the first item of the resulting - * array will be an empty string. - * - * If the string ends with the delimiter and the maximum list size is not - * exceeded, the last array item will be an empty string. - * - * Attention: The array pointer AND all sstr_t.ptr of the array - * items must be manually passed to free(). Use sstrsplit_a() with - * an allocator to managed memory, to avoid this. - * - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * NULL on error - * - * @see sstrsplit_a() - */ -sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); - -/** - * Performing sstrsplit() using a UcxAllocator. - * - * Read the description of sstrsplit() for details. - * - * The memory for the sstr_t.ptr pointers of the array items and the memory for - * the sstr_t array itself are allocated by using the UcxAllocator.malloc() - * function. - * - * Note: the allocator is not used for memory that is freed within the - * same call of this function (locally scoped variables). - * - * @param allocator the UcxAllocator used for allocating memory - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * NULL on error - * - * @see sstrsplit() - */ -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, - ssize_t *count); - -/** - * Compares two UCX strings with standard memcmp(). - * - * At first it compares the sstr_t.length attribute of the two strings. The - * memcmp() function is called, if and only if the lengths match. - * - * @param s1 the first string - * @param s2 the second string - * @return -1, if the length of s1 is less than the length of s2 or 1, if the - * length of s1 is greater than the length of s2 or the result of - * memcmp() otherwise (i.e. 0 if the strings match) - */ -int sstrcmp(sstr_t s1, sstr_t s2); - -/** - * Compares two UCX strings ignoring the case. - * - * At first it compares the sstr_t.length attribute of the two strings. If and - * only if the lengths match, both strings are compared char by char ignoring - * the case. - * - * @param s1 the first string - * @param s2 the second string - * @return -1, if the length of s1 is less than the length of s2 or 1, if the - * length of s1 is greater than the length of s2 or the difference between the - * first two differing characters otherwise (i.e. 0 if the strings match and - * no characters differ) - */ -int sstrcasecmp(sstr_t s1, sstr_t s2); - -/** - * Creates a duplicate of the specified string. - * - * The new sstr_t will contain a copy allocated by standard - * malloc(). So developers MUST pass the sstr_t.ptr to - * free(). - * - * The sstr_t.ptr of the return value will always be NULL- - * terminated. - * - * @param string the string to duplicate - * @return a duplicate of the string - * @see sstrdup_a() - */ -sstr_t sstrdup(sstr_t string); - -/** - * Creates a duplicate of the specified string using a UcxAllocator. - * - * The new sstr_t will contain a copy allocated by the allocators - * ucx_allocator_malloc function. So it is implementation depended, whether the - * returned sstr_t.ptr pointer must be passed to the allocators - * ucx_allocator_free function manually. - * - * The sstr_t.ptr of the return value will always be NULL- - * terminated. - * - * @param allocator a valid instance of a UcxAllocator - * @param string the string to duplicate - * @return a duplicate of the string - * @see sstrdup() - */ -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string); - -/** - * Omits leading and trailing spaces. - * - * This function returns a new sstr_t containing a trimmed version of the - * specified string. - * - * Note: the new sstr_t references the same memory, thus you - * MUST NOT pass the sstr_t.ptr of the return value to - * free(). It is also highly recommended to avoid assignments like - * mystr = sstrtrim(mystr); as you lose the reference to the - * source string. Assignments of this type are only permitted, if the - * sstr_t.ptr of the source string does not need to be freed or if another - * reference to the source string exists. - * - * @param string the string that shall be trimmed - * @return a new sstr_t containing the trimmed string - */ -sstr_t sstrtrim(sstr_t string); - -/** - * Checks, if a string has a specific prefix. - * @param string the string to check - * @param prefix the prefix the string should have - * @return 1, if and only if the string has the specified prefix, 0 otherwise - */ -int sstrprefix(sstr_t string, sstr_t prefix); - -/** - * Checks, if a string has a specific suffix. - * @param string the string to check - * @param suffix the suffix the string should have - * @return 1, if and only if the string has the specified suffix, 0 otherwise - */ -int sstrsuffix(sstr_t string, sstr_t suffix); - -/** - * Returns a lower case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup() for the implications. - * - * @param string the input string - * @return the resulting lower case string - * @see sstrdup() - */ -sstr_t sstrlower(sstr_t string); - -/** - * Returns a lower case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup_a() for the implications. - * - * @param allocator the allocator used for duplicating the string - * @param string the input string - * @return the resulting lower case string - * @see sstrdup_a() - */ -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string); - -/** - * Returns a upper case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup() for the implications. - * - * @param string the input string - * @return the resulting upper case string - * @see sstrdup() - */ -sstr_t sstrupper(sstr_t string); - -/** - * Returns a upper case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup_a() for the implications. - * - * @param allocator the allocator used for duplicating the string - * @param string the input string - * @return the resulting upper case string - * @see sstrdup_a() - */ -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_STRING_H */ diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/test.c --- a/src/ucx/test.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/test.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "test.h" +#include "ucx/test.h" UcxTestSuite* ucx_test_suite_new() { UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite)); @@ -86,6 +86,6 @@ elem->test(suite, output); } fwrite("\nAll test completed.\n", 1, 21, output); - fprintf(output, " Total: %d\n Success: %d\n Failure: %d\n", + fprintf(output, " Total: %u\n Success: %u\n Failure: %u\n", suite->success+suite->failure, suite->success, suite->failure); } diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/test.h --- a/src/ucx/test.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,241 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file: test.h - * - * UCX Test Framework. - * - * Usage of this test framework: - * - * **** IN HEADER FILE: **** - * - *
- * UCX_TEST(function_name)
- * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional
- * 
- * - * **** IN SOURCE FILE: **** - *
- * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) {
- *   // tests with UCX_TEST_ASSERT()
- * }
- * 
- * UCX_TEST(function_name) {
- *   // memory allocation and other stuff here
- *   #UCX_TEST_BEGIN
- *   // tests with UCX_TEST_ASSERT() and/or
- *   // calls with UCX_TEST_CALL_SUBROUTINE() here
- *   #UCX_TEST_END
- *   // cleanup of memory here
- * }
- * 
- * - * Note: if a test fails, a longjump is performed - * back to the #UCX_TEST_BEGIN macro! - * - * Attention: Do not call own functions within a test, that use - * UCX_TEST_ASSERT() macros and are not defined by using UCX_TEST_SUBROUTINE(). - * - * - * @author Mike Becker - * @author Olaf Wintermann - * - */ - -#ifndef UCX_TEST_H -#define UCX_TEST_H - -#include "ucx.h" -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __FUNCTION__ - -/** - * Alias for the __func__ preprocessor macro. - * Some compilers use __func__ and others use __FUNCTION__. - * We use __FUNCTION__ so we define it for those compilers which use - * __func__. - */ -#define __FUNCTION__ __func__ -#endif - -/** Type for the UcxTestSuite. */ -typedef struct UcxTestSuite UcxTestSuite; - -/** Pointer to a test function. */ -typedef void(*UcxTest)(UcxTestSuite*,FILE*); - -/** Type for the internal list of test cases. */ -typedef struct UcxTestList UcxTestList; - -/** Structure for the internal list of test cases. */ -struct UcxTestList { - - /** Test case. */ - UcxTest test; - - /** Pointer to the next list element. */ - UcxTestList *next; -}; - -/** - * A test suite containing multiple test cases. - */ -struct UcxTestSuite { - - /** The number of successful tests after the suite has been run. */ - unsigned int success; - - /** The number of failed tests after the suite has been run. */ - unsigned int failure; - - /** - * Internal list of test cases. - * Use ucx_test_register() to add tests to this list. - */ - UcxTestList *tests; -}; - -/** - * Creates a new test suite. - * @return a new test suite - */ -UcxTestSuite* ucx_test_suite_new(); - -/** - * Destroys a test suite. - * @param suite the test suite to destroy - */ -void ucx_test_suite_free(UcxTestSuite* suite); - -/** - * Registers a test function with the specified test suite. - * - * @param suite the suite, the test function shall be added to - * @param test the test function to register - * @return EXIT_SUCCESS on success or - * EXIT_FAILURE on failure - */ -int ucx_test_register(UcxTestSuite* suite, UcxTest test); - -/** - * Runs a test suite and writes the test log to the specified stream. - * @param suite the test suite to run - * @param outstream the stream the log shall be written to - */ -void ucx_test_run(UcxTestSuite* suite, FILE* outstream); - -/** - * Macro for a #UcxTest function header. - * - * Use this macro to declare and/or define a #UcxTest function. - * - * @param name the name of the test function - */ -#define UCX_TEST(name) void name(UcxTestSuite* _suite_,FILE *_output_) - -/** - * Marks the begin of a test. - * Note: Any UCX_TEST_ASSERT() calls must be performed after - * #UCX_TEST_BEGIN. - * - * @see #UCX_TEST_END - */ -#define UCX_TEST_BEGIN fwrite("Running ", 1, 8, _output_);\ - fwrite(__FUNCTION__, 1, strlen(__FUNCTION__), _output_);\ - fwrite("... ", 1, 4, _output_);\ - jmp_buf _env_; \ - if (!setjmp(_env_)) { - -/** - * Checks a test assertion. - * If the assertion is correct, the test carries on. If the assertion is not - * correct, the specified message (terminated by a dot and a line break) is - * written to the test suites output stream. - * @param condition the condition to check - * @param message the message that shall be printed out on failure - */ -#define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \ - fwrite(message".\n", 1, 2+strlen(message), _output_); \ - _suite_->failure++; \ - longjmp(_env_, 1);\ - } - -/** - * Macro for a test subroutine function header. - * - * Use this to declare and/or define a subroutine that can be called by using - * UCX_TEST_CALL_SUBROUTINE(). - * - * @param name the name of the subroutine - * @param ... the parameter list - * - * @see UCX_TEST_CALL_SUBROUTINE() - */ -#define UCX_TEST_SUBROUTINE(name,...) void name(UcxTestSuite* _suite_,\ - FILE *_output_, jmp_buf _env_, __VA_ARGS__) - -/** - * Macro for calling a test subroutine. - * - * Subroutines declared with UCX_TEST_SUBROUTINE() can be called by using this - * macro. - * - * Note: You may only call subroutines within a #UCX_TEST_BEGIN- - * #UCX_TEST_END-block. - * - * @param name the name of the subroutine - * @param ... the argument list - * - * @see UCX_TEST_SUBROUTINE() - */ -#define UCX_TEST_CALL_SUBROUTINE(name,...) \ - name(_suite_,_output_,_env_,__VA_ARGS__); - -/** - * Marks the end of a test. - * Note: Any UCX_TEST_ASSERT() calls must be performed before - * #UCX_TEST_END. - * - * @see #UCX_TEST_BEGIN - */ -#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;} - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_TEST_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx.c --- a/src/ucx/ucx.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/ucx.c Tue Aug 25 12:07:56 2020 +0200 @@ -2,14 +2,23 @@ * @mainpage UAP Common Extensions * Library with common and useful functions, macros and data structures. *

- * Latest available source:
+ * Latest available source:
+ * + * https://sourceforge.net/projects/ucx/files/ + *

+ * + *

+ * Repositories:
+ * + * https://sourceforge.net/p/ucx/code + * - or - * * https://develop.uap-core.de/hg/ucx *

* *

LICENCE

* - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -34,4 +43,20 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "ucx.h" +#include "ucx/ucx.h" + +int ucx_szmul_impl(size_t a, size_t b, size_t *result) { + if(a == 0 || b == 0) { + *result = 0; + return 0; + } + size_t r = a * b; + if(r / b == a) { + *result = r; + return 0; + } else { + *result = 0; + return 1; + } +} + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx.h --- a/src/ucx/ucx.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Main UCX Header providing most common definitions. - * - * @file ucx.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_H -#define UCX_H - -/** Major UCX version as integer constant. */ -#define UCX_VERSION_MAJOR 0 - -/** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 10 - -#include - -#ifdef _WIN32 -#if !(defined __ssize_t_defined || defined _SSIZE_T_) -#include -typedef SSIZE_T ssize_t; -#define __ssize_t_defined -#define _SSIZE_T_ -#endif /* __ssize_t_defined and _SSIZE_T */ -#else /* !_WIN32 */ -#include -#endif /* _WIN32 */ - -#ifdef __cplusplus -#ifndef _Bool -#define _Bool bool -#define restrict -#endif -/** Use C naming even when compiling with C++. */ -#define UCX_EXTERN extern "C" -extern "C" { -#else -/** Pointless in C. */ -#define UCX_EXTERN -#endif - - -/** - * A function pointer to a destructor function. - * @see ucx_mempool_setdestr() - * @see ucx_mempool_regdestr() - */ -typedef void(*ucx_destructor)(void*); - -/** - * Function pointer to a compare function. - * - * The compare function shall take three arguments: the two values that shall be - * compared and optional additional data. - * The function shall then return -1 if the first argument is less than the - * second argument, 1 if the first argument is greater than the second argument - * and 0 if both arguments are equal. If the third argument is - * NULL, it shall be ignored. - */ -typedef int(*cmp_func)(void*,void*,void*); - -/** - * Function pointer to a copy function. - * - * The copy function shall create a copy of the first argument and may use - * additional data provided by the second argument. If the second argument is - * NULL, it shall be ignored. - - * Attention: if pointers returned by functions of this type may be - * passed to free() depends on the implementation of the - * respective copy_func. - */ -typedef void*(*copy_func)(void*,void*); - -/** - * Function pointer to a write function. - * - * The signature of the write function shall be compatible to the signature - * of standard fwrite, though it may use arbitrary data types for - * source and destination. - * - * The arguments shall contain (in ascending order): a pointer to the source, - * the length of one element, the element count and a pointer to the - * destination. - */ -typedef size_t(*write_func)(const void*, size_t, size_t, void*); - -/** - * Function pointer to a read function. - * - * The signature of the read function shall be compatible to the signature - * of standard fread, though it may use arbitrary data types for - * source and destination. - * - * The arguments shall contain (in ascending order): a pointer to the - * destination, the length of one element, the element count and a pointer to - * the source. - */ -typedef size_t(*read_func)(void*, size_t, size_t, void*); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/allocator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/allocator.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,206 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Allocator for custom memory management. + * + * A UCX allocator consists of a pointer to the memory area / pool and four + * function pointers to memory management functions operating on this memory + * area / pool. These functions shall behave equivalent to the standard libc + * functions malloc(), calloc(), realloc() and free(). + * + * The signature of the memory management functions is based on the signature + * of the respective libc function but each of them takes the pointer to the + * memory area / pool as first argument. + * + * As the pointer to the memory area / pool can be arbitrarily chosen, any data + * can be provided to the memory management functions. A UcxMempool is just + * one example. + * + * @see mempool.h + * @see UcxMap + * + * @file allocator.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_ALLOCATOR_H +#define UCX_ALLOCATOR_H + +#include "ucx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A function pointer to the allocators malloc() function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); + +/** + * A function pointer to the allocators calloc() function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); + +/** + * A function pointer to the allocators realloc() function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); + +/** + * A function pointer to the allocators free() function. + * @see UcxAllocator + */ +typedef void(*ucx_allocator_free)(void *pool, void *data); + +/** + * UCX allocator data structure containing memory management functions. + */ +typedef struct { + /** Pointer to an area of memory or a complex memory pool. + * This pointer will be passed to any memory management function as first + * argument. + */ + void *pool; + /** + * The malloc() function for this allocator. + */ + ucx_allocator_malloc malloc; + /** + * The calloc() function for this allocator. + */ + ucx_allocator_calloc calloc; + /** + * The realloc() function for this allocator. + */ + ucx_allocator_realloc realloc; + /** + * The free() function for this allocator. + */ + ucx_allocator_free free; +} UcxAllocator; + +/** + * Returns a pointer to the default allocator. + * + * The default allocator contains wrappers to the standard libc memory + * management functions. Use this function to get a pointer to a globally + * available allocator. You may also define an own UcxAllocator by assigning + * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable + * to any function that takes a UcxAllocator as argument. Note that using + * this function is the recommended way of passing a default allocator, thus + * it never runs out of scope. + * + * @return a pointer to the default allocator + * + * @see UCX_ALLOCATOR_DEFAULT + */ +UcxAllocator *ucx_default_allocator(); + +/** + * A wrapper for the standard libc malloc() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param n argument passed to malloc() + * @return return value of malloc() + */ +void *ucx_default_malloc(void *ignore, size_t n); +/** + * A wrapper for the standard libc calloc() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param n argument passed to calloc() + * @param size argument passed to calloc() + * @return return value of calloc() + */ +void *ucx_default_calloc(void *ignore, size_t n, size_t size); +/** + * A wrapper for the standard libc realloc() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param data argumend passed to realloc() + * @param n argument passed to realloc() + * @return return value of realloc() + */ +void *ucx_default_realloc(void *ignore, void *data, size_t n); +/** + * A wrapper for the standard libc free() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param data argument passed to free() + */ +void ucx_default_free(void *ignore, void *data); + +/** + * Shorthand for calling an allocators malloc function. + * @param allocator the allocator to use + * @param n size of space to allocate + * @return a pointer to the allocated memory area + */ +#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n)) + +/** + * Shorthand for calling an allocators calloc function. + * @param allocator the allocator to use + * @param n the count of elements the space should be allocated for + * @param size the size of each element + * @return a pointer to the allocated memory area + */ +#define alcalloc(allocator, n, size) \ + ((allocator)->calloc((allocator)->pool, n, size)) + +/** + * Shorthand for calling an allocators realloc function. + * @param allocator the allocator to use + * @param ptr the pointer to the memory area that shall be reallocated + * @param n the new size of the allocated memory area + * @return a pointer to the reallocated memory area + */ +#define alrealloc(allocator, ptr, n) \ + ((allocator)->realloc((allocator)->pool, ptr, n)) + +/** + * Shorthand for calling an allocators free function. + * @param allocator the allocator to use + * @param ptr the pointer to the memory area that shall be freed + */ +#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr)) + +/** + * Convenient macro for a default allocator struct definition. + */ +#define UCX_ALLOCATOR_DEFAULT {NULL, \ + ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \ + ucx_default_free } + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_ALLOCATOR_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/array.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/array.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,517 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2019 Mike Becker, 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. + */ +/** + * Dynamically allocated array implementation. + * + * @file array.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_ARRAY_H +#define UCX_ARRAY_H + +#include "ucx.h" +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX array type. + */ +typedef struct { + /** + * The current capacity of the array. + */ + size_t capacity; + /** + * The actual number of elements in the array. + */ + size_t size; + /** + * The size of an individual element in bytes. + */ + size_t elemsize; + /** + * A pointer to the data. + */ + void* data; + /** + * The allocator used for the data. + */ + UcxAllocator* allocator; +} UcxArray; + +/** + * Sets an element in an arbitrary user defined array. + * + * 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 elmsize the size of each element + * @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) + */ +#define ucx_array_util_set(array, capacity, elmsize, idx, data) \ + ucx_array_util_set_a(ucx_default_allocator(), (void**)(array), capacity, \ + 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. + * + * 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 elmsize the size of each element + * @param idx the index of the element to set + * @param ... 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, ...); + + +/** + * Convenience macro for ucx_array_util_set_a() which automatically computes + * sizeof(data). + * + * @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 + * @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) + +/** + * Creates a new UCX array with the given capacity and element size. + * @param capacity the initial capacity + * @param elemsize the element size + * @return a pointer to a new UCX array structure + */ +UcxArray* ucx_array_new(size_t capacity, size_t elemsize); + +/** + * Creates a new UCX array using the specified allocator. + * + * @param capacity the initial capacity + * @param elemsize the element size + * @param allocator the allocator to use + * @return a pointer to new UCX array structure + */ +UcxArray* ucx_array_new_a(size_t capacity, size_t elemsize, + UcxAllocator* allocator); + +/** + * Initializes a UCX array structure with the given capacity and element size. + * The structure must be uninitialized as the data pointer will be overwritten. + * + * @param array the structure to initialize + * @param capacity the initial capacity + * @param elemsize the element size + */ +void ucx_array_init(UcxArray* array, size_t capacity, size_t elemsize); + +/** + * Initializes a UCX array structure using the specified allocator. + * The structure must be uninitialized as the data pointer will be overwritten. + * + * @param array the structure to initialize + * @param capacity the initial capacity + * @param elemsize the element size + * @param allocator the allocator to use + */ +void ucx_array_init_a(UcxArray* array, size_t capacity, size_t elemsize, + UcxAllocator* allocator); + +/** + * Creates an shallow copy of an array. + * + * This function clones the specified array by using memcpy(). + * If the destination capacity is insufficient, an automatic reallocation is + * attempted. + * + * Note: if the destination array is uninitialized, the behavior is undefined. + * + * @param dest the array to copy to + * @param src the array to copy from + * @return zero on success, non-zero on reallocation failure. + */ +int ucx_array_clone(UcxArray* dest, UcxArray const* src); + + +/** + * Compares two UCX arrays element-wise by using a compare function. + * + * Elements of the two specified arrays are compared by using the specified + * compare function and the additional data. The type and content of this + * additional data depends on the cmp_func() used. + * + * This function always returns zero, if the element sizes of the arrays do + * not match and performs no comparisons in this case. + * + * @param array1 the first array + * @param array2 the second array + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the two arrays equal element-wise, 0 otherwise + */ +int ucx_array_equals(UcxArray const *array1, UcxArray const *array2, + cmp_func cmpfnc, void* data); + +/** + * Destroys the array. + * + * The data is freed and both capacity and count are reset to zero. + * If the array structure itself has been dynamically allocated, it has to be + * freed separately. + * + * @param array the array to destroy + */ +void ucx_array_destroy(UcxArray *array); + +/** + * Destroys and frees the array. + * + * @param array the array to free + */ +void ucx_array_free(UcxArray *array); + +/** + * Inserts elements at the end of the array. + * + * This is an O(1) operation. + * The array will automatically grow, if the capacity is exceeded. + * If a pointer to data is provided, the data is copied into the array with + * memcpy(). Otherwise the new elements are completely zeroed. + * + * @param array a pointer the array where to append the data + * @param data a pointer to the data to insert (may be NULL) + * @param count number of elements to copy from data (if data is + * NULL, zeroed elements are appended) + * @return zero on success, non-zero if a reallocation was necessary but failed + * @see ucx_array_set_from() + * @see ucx_array_append() + */ +int ucx_array_append_from(UcxArray *array, void *data, size_t count); + + +/** + * Inserts elements 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_from() instead. + * + * @param array a pointer the array where to prepend the data + * @param data a pointer to the data to insert (may be NULL) + * @param count number of elements to copy from data (if data is + * NULL, zeroed elements are inserted) + * @return zero on success, non-zero if a reallocation was necessary but failed + * @see ucx_array_append_from() + * @see ucx_array_set_from() + * @see ucx_array_prepend() + */ +int ucx_array_prepend_from(UcxArray *array, void *data, size_t count); + + +/** + * Sets elements starting at the specified index. + * + * If the any index is out of bounds, the array automatically grows. + * The pointer to the data may be NULL, in which case the elements are zeroed. + * + * @param array a pointer the array where to set the data + * @param index the index of the element to set + * @param data a pointer to the data to insert (may be NULL) + * @param count number of elements to copy from data (if data is + * NULL, the memory in the array is zeroed) + * @return zero on success, non-zero if a reallocation was necessary but failed + * @see ucx_array_append_from() + * @see ucx_array_set() + */ +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 + * single operation. The second array is otherwise left untouched. + * + * The first array may grow automatically. If this fails, both arrays remain + * unmodified. + * + * @param array1 first array + * @param array2 second array + * @return zero on success, non-zero if reallocation was necessary but failed + * or the element size does not match + */ +int ucx_array_concat(UcxArray *array1, const UcxArray *array2); + +/** + * Returns a pointer to the array element at the specified index. + * + * @param array the array to retrieve the element from + * @param index index of the element to return + * @return a pointer to the element at the specified index or NULL, + * if the index is greater than the array size + */ +void *ucx_array_at(UcxArray const* array, size_t index); + +/** + * Returns the index of an element containing the specified data. + * + * This function uses a cmp_func() to compare the data of each list element + * with the specified data. If no cmp_func is provided, memcmp() is used. + * + * If the array contains the data more than once, the index of the first + * occurrence is returned. + * If the array does not contain the data, the size of array is returned. + * + * @param array the array where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return the index of the element containing the specified data or the size of + * the array, if the data is not found in this array + */ +size_t ucx_array_find(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data); + +/** + * Checks, if an array contains a specific element. + * + * An element is found, if ucx_array_find() returns a value less than the size. + * + * @param array the array where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the array contains the specified element data + * @see ucx_array_find() + */ +int ucx_array_contains(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data); + +/** + * Sorts a UcxArray with the best available sort algorithm. + * + * The qsort_r() function is used, if available (glibc, FreeBSD or MacOS). + * The order of arguments is automatically adjusted for the FreeBSD and MacOS + * version of qsort_r(). + * + * If qsort_r() is not available, a merge sort algorithm is used, which is + * guaranteed to use no more additional memory than for exactly one element. + * + * @param array the array to sort + * @param cmpfnc the function that shall be used to compare the element data + * @param data additional data for the cmp_func() or NULL + */ +void ucx_array_sort(UcxArray* array, cmp_func cmpfnc, void *data); + +/** + * Removes an element from the array. + * + * This is in general an expensive operation, because several elements may + * be moved. If the order of the elements is not relevant, use + * ucx_array_remove_fast() instead. + * + * @param array pointer to the array from which the element shall be removed + * @param index the index of the element to remove + */ +void ucx_array_remove(UcxArray *array, size_t index); + +/** + * Removes an element from the array. + * + * This is an O(1) operation, but does not maintain the order of the elements. + * The last element in the array is moved to the location of the removed + * element. + * + * @param array pointer to the array from which the element shall be removed + * @param index the index of the element to remove + */ +void ucx_array_remove_fast(UcxArray *array, size_t index); + +/** + * Shrinks the memory to exactly fit the contents. + * + * After this operation, the capacity equals the size. + * + * @param array a pointer to the array + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_shrink(UcxArray* array); + +/** + * Sets the capacity of the array. + * + * If the new capacity is smaller than the size of the array, the elements + * are removed and the size is adjusted accordingly. + * + * @param array a pointer to the array + * @param capacity the new capacity + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_resize(UcxArray* array, size_t capacity); + +/** + * Resizes the array only, if the capacity is insufficient. + * + * If the requested capacity is smaller than the current capacity, this + * function does nothing. + * + * @param array a pointer to the array + * @param capacity the guaranteed capacity + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_reserve(UcxArray* array, size_t capacity); + + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_ARRAY_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/avl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/avl.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,353 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @file avl.h + * + * AVL tree implementation. + * + * This binary search tree implementation allows average O(1) insertion and + * removal of elements (excluding binary search time). + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_AVL_H +#define UCX_AVL_H + +#include "ucx.h" +#include "allocator.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX AVL Node type. + * + * @see UcxAVLNode + */ +typedef struct UcxAVLNode UcxAVLNode; + +/** + * UCX AVL Node. + */ +struct UcxAVLNode { + /** + * The key for this node. + */ + intptr_t key; + /** + * Data contained by this node. + */ + void *value; + /** + * The height of this (sub)-tree. + */ + size_t height; + /** + * Parent node. + */ + UcxAVLNode *parent; + /** + * Root node of left subtree. + */ + UcxAVLNode *left; + /** + * Root node of right subtree. + */ + UcxAVLNode *right; +}; + +/** + * UCX AVL Tree. + */ +typedef struct { + /** + * The UcxAllocator that shall be used to manage the memory for node data. + */ + UcxAllocator *allocator; + /** + * Root node of the tree. + */ + UcxAVLNode *root; + /** + * Compare function that shall be used to compare the UcxAVLNode keys. + * @see UcxAVLNode.key + */ + cmp_func cmpfunc; + /** + * Custom user data. + * This data will also be provided to the cmpfunc. + */ + void *userdata; +} UcxAVLTree; + +/** + * Initializes a new UcxAVLTree with a default allocator. + * + * @param cmpfunc the compare function that shall be used + * @return a new UcxAVLTree object + * @see ucx_avl_new_a() + */ +UcxAVLTree *ucx_avl_new(cmp_func cmpfunc); + +/** + * Initializes a new UcxAVLTree with the specified allocator. + * + * The cmpfunc should be capable of comparing two keys within this AVL tree. + * So if you want to use null terminated strings as keys, you could use the + * ucx_cmp_str() function here. + * + * @param cmpfunc the compare function that shall be used + * @param allocator the UcxAllocator that shall be used + * @return a new UcxAVLTree object + */ +UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator); + +/** + * Destroys a UcxAVLTree. + * + * Note, that the contents are not automatically freed. + * Use may use #ucx_avl_free_content() before calling this function. + * + * @param tree the tree to destroy + * @see ucx_avl_free_content() + */ +void ucx_avl_free(UcxAVLTree *tree); + +/** + * Frees the contents of a UcxAVLTree. + * + * This is a convenience function that iterates over the tree and passes all + * values to the specified destructor function. + * + * If no destructor is specified (NULL), the free() function of + * the tree's own allocator is used. + * + * You must ensure, that it is valid to pass each value in the map to the same + * destructor function. + * + * You should free the entire tree afterwards, as the contents will be invalid. + * + * @param tree for which the contents shall be freed + * @param destr optional pointer to a destructor function + * @see ucx_avl_free() + */ +void ucx_avl_free_content(UcxAVLTree *tree, ucx_destructor destr); + +/** + * Macro for initializing a new UcxAVLTree with the default allocator and a + * ucx_cmp_ptr() compare function. + * + * @return a new default UcxAVLTree object + */ +#define ucx_avl_default_new() \ + ucx_avl_new_a(ucx_cmp_ptr, ucx_default_allocator()) + +/** + * Gets the node from the tree, that is associated with the specified key. + * @param tree the UcxAVLTree + * @param key the key + * @return the node (or NULL, if the key is not present) + */ +UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key); + +/** + * Gets the value from the tree, that is associated with the specified key. + * @param tree the UcxAVLTree + * @param key the key + * @return the value (or NULL, if the key is not present) + */ +void *ucx_avl_get(UcxAVLTree *tree, intptr_t key); + +/** + * A mode for #ucx_avl_find_node() with the same behavior as + * #ucx_avl_get_node(). + */ +#define UCX_AVL_FIND_EXACT 0 +/** + * A mode for #ucx_avl_find_node() finding the node whose key is at least + * as large as the specified key. + */ +#define UCX_AVL_FIND_LOWER_BOUNDED 1 +/** + * A mode for #ucx_avl_find_node() finding the node whose key is at most + * as large as the specified key. + */ +#define UCX_AVL_FIND_UPPER_BOUNDED 2 +/** + * A mode for #ucx_avl_find_node() finding the node with a key that is as close + * to the specified key as possible. If the key is present, the behavior is + * like #ucx_avl_get_node(). This mode only returns NULL on + * empty trees. + */ +#define UCX_AVL_FIND_CLOSEST 3 + +/** + * Finds a node within the tree. The following modes are supported: + *
    + *
  • #UCX_AVL_FIND_EXACT: the same behavior as #ucx_avl_get_node()
  • + *
  • #UCX_AVL_FIND_LOWER_BOUNDED: finds the node whose key is at least + * as large as the specified key
  • + *
  • #UCX_AVL_FIND_UPPER_BOUNDED: finds the node whose key is at most + * as large as the specified key
  • + *
  • #UCX_AVL_FIND_CLOSEST: finds the node with a key that is as close to + * the specified key as possible. If the key is present, the behavior is + * like #ucx_avl_get_node(). This mode only returns NULL on + * empty trees.
  • + *
+ * + * The distance function provided MUST agree with the compare function of + * the AVL tree. + * + * @param tree the UcxAVLTree + * @param key the key + * @param dfnc the distance function + * @param mode the find mode + * @return the node (or NULL, if no node can be found) + */ +UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode); + +/** + * Finds a value within the tree. + * See #ucx_avl_find_node() for details. + * + * @param tree the UcxAVLTree + * @param key the key + * @param dfnc the distance function + * @param mode the find mode + * @return the value (or NULL, if no value can be found) + */ +void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode); + +/** + * Puts a key/value pair into the tree. + * + * Attention: use this function only, if a possible old value does not need + * to be preserved. + * + * @param tree the UcxAVLTree + * @param key the key + * @param value the new value + * @return zero, if and only if the operation succeeded + */ +int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value); + +/** + * Puts a key/value pair into the tree. + * + * This is a secure function which saves the old value to the variable pointed + * at by oldvalue. + * + * @param tree the UcxAVLTree + * @param key the key + * @param value the new value + * @param oldvalue optional: a pointer to the location where a possible old + * value shall be stored + * @return zero, if and only if the operation succeeded + */ +int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, void **oldvalue); + +/** + * Removes a node from the AVL tree. + * + * Note: the specified node is logically removed. The tree implementation + * decides which memory area is freed. In most cases the here provided node + * is freed, so its further use is generally undefined. + * + * @param tree the UcxAVLTree + * @param node the node to remove + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node); + +/** + * Removes an element from the AVL tree. + * + * @param tree the UcxAVLTree + * @param key the key + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove(UcxAVLTree *tree, intptr_t key); + +/** + * Removes an element from the AVL tree. + * + * This is a secure function which saves the old key and value data from node + * to the variables at the location of oldkey and oldvalue (if specified), so + * they can be freed afterwards (if necessary). + * + * Note: the returned key in oldkey is possibly not the same as the provided + * key for the lookup (in terms of memory location). + * + * @param tree the UcxAVLTree + * @param key the key of the element to remove + * @param oldkey optional: a pointer to the location where the old key shall be + * stored + * @param oldvalue optional: a pointer to the location where the old value + * shall be stored + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, + intptr_t *oldkey, void **oldvalue); + +/** + * Counts the nodes in the specified UcxAVLTree. + * @param tree the AVL tree + * @return the node count + */ +size_t ucx_avl_count(UcxAVLTree *tree); + +/** + * Finds the in-order predecessor of the given node. + * @param node an AVL node + * @return the in-order predecessor of the given node, or NULL if + * the given node is the in-order minimum + */ +UcxAVLNode* ucx_avl_pred(UcxAVLNode* node); + +/** + * Finds the in-order successor of the given node. + * @param node an AVL node + * @return the in-order successor of the given node, or NULL if + * the given node is the in-order maximum + */ +UcxAVLNode* ucx_avl_succ(UcxAVLNode* node); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_AVL_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/buffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/buffer.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,339 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file buffer.h + * + * Advanced buffer implementation. + * + * Instances of UcxBuffer can be used to read from or to write to like one + * would do with a stream. This allows the use of ucx_stream_copy() to copy + * contents from one buffer to another. + * + * Some features for convenient use of the buffer + * can be enabled. See the documentation of the macro constants for more + * information. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_BUFFER_H +#define UCX_BUFFER_H + +#include "ucx.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * No buffer features enabled (all flags cleared). + */ +#define UCX_BUFFER_DEFAULT 0x00 + +/** + * If this flag is enabled, the buffer will automatically free its contents. + */ +#define UCX_BUFFER_AUTOFREE 0x01 + +/** + * If this flag is enabled, the buffer will automatically extends its capacity. + */ +#define UCX_BUFFER_AUTOEXTEND 0x02 + +/** UCX Buffer. */ +typedef struct { + /** A pointer to the buffer contents. */ + char *space; + /** Current position of the buffer. */ + size_t pos; + /** Current capacity (i.e. maximum size) of the buffer. */ + size_t capacity; + /** Current size of the buffer content. */ + size_t size; + /** + * Flag register for buffer features. + * @see #UCX_BUFFER_DEFAULT + * @see #UCX_BUFFER_AUTOFREE + * @see #UCX_BUFFER_AUTOEXTEND + */ + int flags; +} UcxBuffer; + +/** + * Creates a new buffer. + * + * Note: you may provide NULL as argument for + * space. Then this function will allocate the space and enforce + * the #UCX_BUFFER_AUTOFREE flag. + * + * @param space pointer to the memory area, or NULL to allocate + * new memory + * @param capacity the capacity of the buffer + * @param flags buffer features (see UcxBuffer.flags) + * @return the new buffer + */ +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); + +/** + * Destroys a buffer. + * + * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer + * are also freed. + * + * @param buffer the buffer to destroy + */ +void ucx_buffer_free(UcxBuffer* buffer); + +/** + * Creates a new buffer and fills it with extracted content from another buffer. + * + * Note: the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. + * + * @param src the source buffer + * @param start the start position of extraction + * @param length the count of bytes to extract (must not be zero) + * @param flags feature mask for the new buffer + * @return a new buffer containing the extraction + */ +UcxBuffer* ucx_buffer_extract(UcxBuffer *src, + size_t start, size_t length, int flags); + +/** + * A shorthand macro for the full extraction of the buffer. + * + * @param src the source buffer + * @param flags feature mask for the new buffer + * @return a new buffer with the extracted content + */ +#define ucx_buffer_clone(src,flags) \ + ucx_buffer_extract(src, 0, (src)->capacity, flags) + + +/** + * Shifts the contents of the buffer by the given offset. + * + * If the offset is positive, the contents are shifted to the right. + * If auto extension is enabled, the buffer grows, if necessary. + * In case the auto extension fails, this function returns a non-zero value and + * no contents are changed. + * If auto extension is disabled, the contents that do not fit into the buffer + * are discarded. + * + * If the offset is negative, the contents are shifted to the left where the + * first shift bytes are discarded. + * The new size of the buffer is the old size minus + * the absolute shift value. + * If this value is larger than the buffer size, the buffer is emptied (but + * not cleared, see the security note below). + * + * The buffer position gets shifted alongside with the content but is kept + * within the boundaries of the buffer. + * + * Security note: the shifting operation does not erase the + * previously occupied memory cells. You can easily do that manually, e.g. by + * calling memset(buffer->space, 0, shift) for a right shift or + * memset(buffer->size, 0, buffer->capacity-buffer->size) + * for a left shift. + * + * @param buffer the buffer + * @param shift the shift offset (negative means left shift) + * @return 0 on success, non-zero if a required auto-extension fails + */ +int ucx_buffer_shift(UcxBuffer* buffer, off_t shift); + +/** + * Shifts the buffer to the right. + * See ucx_buffer_shift() for details. + * + * @param buffer the buffer + * @param shift the shift offset + * @return 0 on success, non-zero if a required auto-extension fails + * @see ucx_buffer_shift() + */ +int ucx_buffer_shift_right(UcxBuffer* buffer, size_t shift); + +/** + * Shifts the buffer to the left. + * + * See ucx_buffer_shift() for details. Note, however, that this method expects + * a positive shift offset. + * + * Since a left shift cannot fail due to memory allocation problems, this + * function always returns zero. + * + * @param buffer the buffer + * @param shift the shift offset + * @return always zero + * @see ucx_buffer_shift() + */ +int ucx_buffer_shift_left(UcxBuffer* buffer, size_t shift); + + +/** + * Moves the position of the buffer. + * + * The new position is relative to the whence argument. + * + * SEEK_SET marks the start of the buffer. + * SEEK_CUR marks the current position. + * SEEK_END marks the end of the buffer. + * + * With an offset of zero, this function sets the buffer position to zero + * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position + * unchanged (SEEK_CUR). + * + * @param buffer + * @param offset position offset relative to whence + * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END + * @return 0 on success, non-zero if the position is invalid + * + */ +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); + +/** + * Clears the buffer by resetting the position and deleting the data. + * + * The data is deleted by a zeroing it with call to memset(). + * + * @param buffer the buffer to be cleared + */ +#define ucx_buffer_clear(buffer) memset((buffer)->space, 0, (buffer)->size); \ + (buffer)->size = 0; (buffer)->pos = 0; + +/** + * Tests, if the buffer position has exceeded the buffer capacity. + * + * @param buffer the buffer to test + * @return non-zero, if the current buffer position has exceeded the last + * available byte of the buffer. + */ +int ucx_buffer_eof(UcxBuffer *buffer); + + +/** + * Extends the capacity of the buffer. + * + * Note: The buffer capacity increased by a power of two. I.e. + * the buffer capacity is doubled, as long as it would not hold the current + * content plus the additional required bytes. + * + * Attention: the argument provided is the number of additional + * bytes the buffer shall hold. It is NOT the total number of bytes the + * buffer shall hold. + * + * @param buffer the buffer to extend + * @param additional_bytes the number of additional bytes the buffer shall + * at least hold + * @return 0 on success or a non-zero value on failure + */ +int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); + +/** + * Writes data to a UcxBuffer. + * + * The position of the buffer is increased by the number of bytes written. + * + * @param ptr a pointer to the memory area containing the bytes to be written + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to write to + * @return the total count of bytes written + */ +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/** + * Reads data from a UcxBuffer. + * + * The position of the buffer is increased by the number of bytes read. + * + * @param ptr a pointer to the memory area where to store the read data + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to read from + * @return the total number of elements read + */ +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/** + * Writes a character to a buffer. + * + * The least significant byte of the argument is written to the buffer. If the + * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, + * the buffer capacity is extended by ucx_buffer_extend(). If the feature is + * disabled or buffer extension fails, EOF is returned. + * + * On successful write the position of the buffer is increased. + * + * @param buffer the buffer to write to + * @param c the character to write as int value + * @return the byte that has bean written as int value or + * EOF when the end of the stream is reached and automatic + * extension is not enabled or not possible + */ +int ucx_buffer_putc(UcxBuffer *buffer, int c); + +/** + * Gets a character from a buffer. + * + * The current position of the buffer is increased after a successful read. + * + * @param buffer the buffer to read from + * @return the character as int value or EOF, if the + * end of the buffer is reached + */ +int ucx_buffer_getc(UcxBuffer *buffer); + +/** + * Writes a string to a buffer. + * + * @param buffer the buffer + * @param str the string + * @return the number of bytes written + */ +size_t ucx_buffer_puts(UcxBuffer *buffer, const char *str); + +/** + * Returns the complete buffer content as sstr_t. + * @param buffer the buffer + * @return the result of sstrn() with the buffer space and size + * as arguments + */ +#define ucx_buffer_to_sstr(buffer) sstrn((buffer)->space, (buffer)->size) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_BUFFER_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/list.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,396 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Doubly linked list implementation. + * + * @file list.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_LIST_H +#define UCX_LIST_H + +#include "ucx.h" +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Loop statement for UCX lists. + * + * The first argument is the name of the iteration variable. The scope of + * this variable is limited to the UCX_FOREACH statement. + * + * The second argument is a pointer to the list. In most cases this will be the + * pointer to the first element of the list, but it may also be an arbitrary + * element of the list. The iteration will then start with that element. + * + * @param list The first element of the list + * @param elem The variable name of the element + */ +#define UCX_FOREACH(elem,list) \ + for (UcxList* elem = list ; elem != NULL ; elem = elem->next) + +/** + * UCX list type. + * @see UcxList + */ +typedef struct UcxList UcxList; + +/** + * UCX list structure. + */ +struct UcxList { + /** + * List element payload. + */ + void *data; + /** + * Pointer to the next list element or NULL, if this is the + * last element. + */ + UcxList *next; + /** + * Pointer to the previous list element or NULL, if this is + * the first element. + */ + UcxList *prev; +}; + +/** + * Creates an element-wise copy of a list. + * + * This function clones the specified list by creating new list elements and + * copying the data with the specified copy_func(). If no copy_func() is + * specified, a shallow copy is created and the new list will reference the + * same data as the source list. + * + * @param list the list to copy + * @param cpyfnc a pointer to the function that shall copy an element (may be + * NULL) + * @param data additional data for the copy_func() + * @return a pointer to the copy + */ +UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); + +/** + * Creates an element-wise copy of a list using a UcxAllocator. + * + * See ucx_list_clone() for details. + * + * You might want to pass the allocator via the data parameter, + * to access it within the copy function for making deep copies. + * + * @param allocator the allocator to use + * @param list the list to copy + * @param cpyfnc a pointer to the function that shall copy an element (may be + * NULL) + * @param data additional data for the copy_func() + * @return a pointer to the copy + * @see ucx_list_clone() + */ +UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, + copy_func cpyfnc, void* data); + +/** + * Compares two UCX lists element-wise by using a compare function. + * + * Each element of the two specified lists are compared by using the specified + * compare function and the additional data. The type and content of this + * additional data depends on the cmp_func() used. + * + * If the list pointers denote elements within a list, the lists are compared + * starting with the denoted elements. Thus any previous elements are not taken + * into account. This might be useful to check, if certain list tails match + * each other. + * + * @param list1 the first list + * @param list2 the second list + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the two lists equal element-wise, 0 otherwise + */ +int ucx_list_equals(const UcxList *list1, const UcxList *list2, + cmp_func cmpfnc, void* data); + +/** + * Destroys the entire list. + * + * The members of the list are not automatically freed, so ensure they are + * otherwise referenced or destroyed by ucx_list_free_contents(). + * Otherwise, a memory leak is likely to occur. + * + * Caution: the argument MUST denote an entire list (i.e. a call + * to ucx_list_first() on the argument must return the argument itself) + * + * @param list the list to free + * @see ucx_list_free_contents() + */ +void ucx_list_free(UcxList *list); + +/** + * Destroys the entire list using a UcxAllocator. + * + * See ucx_list_free() for details. + * + * @param allocator the allocator to use + * @param list the list to free + * @see ucx_list_free() + */ +void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); + +/** + * Destroys the contents of the specified list by calling the specified + * destructor on each of them. + * + * Note, that the contents are not usable afterwards and the list should be + * destroyed with ucx_list_free(). + * + * If no destructor is specified (NULL), stdlib's free() is used. + * + * @param list the list for which the contents shall be freed + * @param destr optional destructor function + * @see ucx_list_free() + */ +void ucx_list_free_content(UcxList* list, ucx_destructor destr); + + +/** + * Inserts an element at the end of the list. + * + * This is generally an O(n) operation, as the end of the list is retrieved with + * ucx_list_last(). + * + * @param list the list where to append the data, or NULL to + * create a new list + * @param data the data to insert + * @return list, if it is not NULL or a pointer to + * the newly created list otherwise + */ +UcxList *ucx_list_append(UcxList *list, void *data); + +/** + * Inserts an element at the end of the list using a UcxAllocator. + * + * See ucx_list_append() for details. + * + * @param allocator the allocator to use + * @param list the list where to append the data, or NULL to + * create a new list + * @param data the data to insert + * @return list, if it is not NULL or a pointer to + * the newly created list otherwise + * @see ucx_list_append() + */ +UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); + + +/** + * Inserts an element at the beginning of the list. + * + * You should overwrite the old list pointer by calling + * mylist = ucx_list_prepend(mylist, mydata);. However, you may + * also perform successive calls of ucx_list_prepend() on the same list pointer, + * as this function always searchs for the head of the list with + * ucx_list_first(). + * + * @param list the list where to insert the data or NULL to create + * a new list + * @param data the data to insert + * @return a pointer to the new list head + */ +UcxList *ucx_list_prepend(UcxList *list, void *data); + +/** + * Inserts an element at the beginning of the list using a UcxAllocator. + * + * See ucx_list_prepend() for details. + * + * @param allocator the allocator to use + * @param list the list where to insert the data or NULL to create + * a new list + * @param data the data to insert + * @return a pointer to the new list head + * @see ucx_list_prepend() + */ +UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); + +/** + * Concatenates two lists. + * + * Either of the two arguments may be NULL. + * + * This function modifies the references to the next/previous element of + * the last/first element of list1/ + * list2. + * + * @param list1 first list + * @param list2 second list + * @return if list1 is NULL, list2 is + * returned, otherwise list1 is returned + */ +UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); + +/** + * Returns the first element of a list. + * + * If the argument is the list pointer, it is directly returned. Otherwise + * this function traverses to the first element of the list and returns the + * list pointer. + * + * @param elem one element of the list + * @return the first element of the list, the specified element is a member of + */ +UcxList *ucx_list_first(const UcxList *elem); + +/** + * Returns the last element of a list. + * + * If the argument has no successor, it is the last element and therefore + * directly returned. Otherwise this function traverses to the last element of + * the list and returns it. + * + * @param elem one element of the list + * @return the last element of the list, the specified element is a member of + */ +UcxList *ucx_list_last(const UcxList *elem); + +/** + * Returns the list element at the specified index. + * + * @param list the list to retrieve the element from + * @param index index of the element to return + * @return the element at the specified index or NULL, if the + * index is greater than the list size + */ +UcxList *ucx_list_get(const UcxList *list, size_t index); + +/** + * Returns the index of an element. + * + * @param list the list where to search for the element + * @param elem the element to find + * @return the index of the element or -1 if the list does not contain the + * element + */ +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); + +/** + * Returns the element count of the list. + * + * @param list the list whose elements are counted + * @return the element count + */ +size_t ucx_list_size(const UcxList *list); + +/** + * Returns the index of an element containing the specified data. + * + * This function uses a cmp_func() to compare the data of each list element + * with the specified data. If no cmp_func is provided, the pointers are + * compared. + * + * If the list contains the data more than once, the index of the first + * occurrence is returned. + * + * @param list the list where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return the index of the element containing the specified data or -1 if the + * data is not found in this list + */ +ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); + +/** + * Checks, if a list contains a specific element. + * + * An element is found, if ucx_list_find() returns a value greater than -1. + * + * @param list the list where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the list contains the specified element data + * @see ucx_list_find() + */ +int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); + +/** + * Sorts a UcxList with natural merge sort. + * + * This function uses O(n) additional temporary memory for merge operations + * that is automatically freed after each merge. + * + * As the head of the list might change, you MUST call this function + * as follows: mylist = ucx_list_sort(mylist, mycmpfnc, mydata);. + * + * @param list the list to sort + * @param cmpfnc the function that shall be used to compare the element data + * @param data additional data for the cmp_func() + * @return the sorted list + */ +UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); + +/** + * Removes an element from the list. + * + * If the first element is removed, the list pointer changes. So it is + * highly recommended to always update the pointer by calling + * mylist = ucx_list_remove(mylist, myelem);. + * + * @param list the list from which the element shall be removed + * @param element the element to remove + * @return returns the updated list pointer or NULL, if the list + * is now empty + */ +UcxList *ucx_list_remove(UcxList *list, UcxList *element); + +/** + * Removes an element from the list using a UcxAllocator. + * + * See ucx_list_remove() for details. + * + * @param allocator the allocator to use + * @param list the list from which the element shall be removed + * @param element the element to remove + * @return returns the updated list pointer or NULL, if the list + * @see ucx_list_remove() + */ +UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, + UcxList *element); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_LIST_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/logging.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,250 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Logging API. + * + * @file logging.h + * @author Mike Becker, Olaf Wintermann + */ +#ifndef UCX_LOGGING_H +#define UCX_LOGGING_H + +#include "ucx.h" +#include "map.h" +#include "string.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* leave enough space for custom log levels */ + +/** Log level for error messages. */ +#define UCX_LOGGER_ERROR 0x00 + +/** Log level for warning messages. */ +#define UCX_LOGGER_WARN 0x10 + +/** Log level for information messages. */ +#define UCX_LOGGER_INFO 0x20 + +/** Log level for debug messages. */ +#define UCX_LOGGER_DEBUG 0x30 + +/** Log level for trace messages. */ +#define UCX_LOGGER_TRACE 0x40 + +/** + * Output flag for the log level. + * If this flag is set, the log message will contain the log level. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_LEVEL 0x01 + +/** + * Output flag for the timestmap. + * If this flag is set, the log message will contain the timestmap. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_TIMESTAMP 0x02 + +/** + * Output flag for the source. + * If this flag is set, the log message will contain the source file and line + * number. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_SOURCE 0x04 + +/** + * The UCX Logger object. + */ +typedef struct { + /** The stream this logger writes its messages to.*/ + void *stream; + + /** + * The write function that shall be used. + * For standard file or stdout loggers this might be standard fwrite + * (default). + */ + write_func writer; + + /** + * The date format for timestamp outputs including the delimiter + * (default: "%F %T %z "). + * @see UCX_LOGGER_TIMESTAMP + */ + char *dateformat; + + /** + * The level, this logger operates on. + * If a log command is issued, the message will only be logged, if the log + * level of the message is less or equal than the log level of the logger. + */ + unsigned int level; + + /** + * A configuration mask for automatic output. + * For each flag that is set, the logger automatically outputs some extra + * information like the timestamp or the source file and line number. + * See the documentation for the flags for details. + */ + unsigned int mask; + + /** + * A map of valid log levels for this logger. + * + * The keys represent all valid log levels and the values provide string + * representations, that are used, if the UCX_LOGGER_LEVEL flag is set. + * + * The exact data types are unsigned int for the key and + * const char* for the value. + * + * @see UCX_LOGGER_LEVEL + */ + UcxMap* levels; +} UcxLogger; + +/** + * Creates a new logger. + * @param stream the stream, which the logger shall write to + * @param level the level on which the logger shall operate + * @param mask configuration mask (cf. UcxLogger.mask) + * @return a new logger object + */ +UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask); + +/** + * Destroys the logger. + * + * The map containing the valid log levels is also automatically destroyed. + * + * @param logger the logger to destroy + */ +void ucx_logger_free(UcxLogger* logger); + +/** + * Internal log function - use macros instead. + * + * This function uses the format and variadic arguments for a + * printf()-style output of the log message. + * + * Dependent on the UcxLogger.mask some information is prepended. The complete + * format is: + * + * [LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message + * + * 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. + * + * @param logger the logger to use + * @param level the level to log on + * @param file information about the source file + * @param line information about the source line number + * @param format format string + * @param ... arguments + * @see ucx_logger_log() + */ +void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, + const unsigned int line, const char* format, ...); + +/** + * Registers a custom log level. + * @param logger the logger + * @param level the log level as unsigned integer + * @param name a string literal describing the level + */ +#define ucx_logger_register_level(logger, level, name) {\ + unsigned int l; \ + l = level; \ + ucx_map_int_put(logger->levels, l, (void*) "[" name "]"); \ + } while (0); + +/** + * Logs a message at the specified level. + * @param logger the logger to use + * @param level the level to log the message on + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_log(logger, level, ...) \ + ucx_logger_logf(logger, level, __FILE__, __LINE__, __VA_ARGS__) + +/** + * Shortcut for logging an error message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_error(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_ERROR, __VA_ARGS__) + +/** + * Shortcut for logging an information message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_info(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_INFO, __VA_ARGS__) + +/** + * Shortcut for logging a warning message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_warn(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_WARN, __VA_ARGS__) + +/** + * Shortcut for logging a debug message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_debug(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_DEBUG, __VA_ARGS__) + +/** + * Shortcut for logging a trace message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_trace(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_TRACE, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_LOGGING_H */ diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/map.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/map.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,480 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file map.h + * + * Hash map implementation. + * + * This implementation uses murmur hash 2 and separate chaining with linked + * lists. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_MAP_H +#define UCX_MAP_H + +#include "ucx.h" +#include "string.h" +#include "allocator.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Loop statement for UCX maps. + * + * The key variable is implicitly defined, but the + * value variable must be already declared as type information + * cannot be inferred. + * + * @param key the variable name for the key + * @param value the variable name for the value + * @param iter a UcxMapIterator + * @see ucx_map_iterator() + */ +#define UCX_MAP_FOREACH(key,value,iter) \ + for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&value);) + +/** Type for the UCX map. @see UcxMap */ +typedef struct UcxMap UcxMap; + +/** Type for a key of a UcxMap. @see UcxKey */ +typedef struct UcxKey UcxKey; + +/** Type for an element of a UcxMap. @see UcxMapElement */ +typedef struct UcxMapElement UcxMapElement; + +/** Type for an iterator over a UcxMap. @see UcxMapIterator */ +typedef struct UcxMapIterator UcxMapIterator; + +/** Structure for the UCX map. */ +struct UcxMap { + /** An allocator that is used for the map elements. */ + UcxAllocator *allocator; + /** The array of map element lists. */ + UcxMapElement **map; + /** The size of the map is the length of the element list array. */ + size_t size; + /** The count of elements currently stored in this map. */ + size_t count; +}; + +/** Structure to publicly denote a key of a UcxMap. */ +struct UcxKey { + /** The key data. */ + const void *data; + /** The length of the key data. */ + size_t len; + /** A cache for the hash value of the key data. */ + int hash; +}; + +/** Internal structure for a key of a UcxMap. */ +struct UcxMapKey { + /** The key data. */ + void *data; + /** The length of the key data. */ + size_t len; + /** The hash value of the key data. */ + int hash; +}; + +/** Structure for an element of a UcxMap. */ +struct UcxMapElement { + /** The value data. */ + void *data; + + /** A pointer to the next element in the current list. */ + UcxMapElement *next; + + /** The corresponding key. */ + struct UcxMapKey key; +}; + +/** Structure for an iterator over a UcxMap. */ +struct UcxMapIterator { + /** The map to iterate over. */ + UcxMap *map; + + /** The current map element. */ + UcxMapElement *cur; + + /** + * The current index of the element list array. + * Attention: this is NOT the element index! Do NOT + * manually iterate over the map by increasing this index. Use + * ucx_map_iter_next(). + * @see UcxMap.map*/ + size_t index; +}; + +/** + * Creates a new hash map with the specified size. + * @param size the size of the hash map + * @return a pointer to the new hash map + */ +UcxMap *ucx_map_new(size_t size); + +/** + * Creates a new hash map with the specified size using a UcxAllocator. + * @param allocator the allocator to use + * @param size the size of the hash map + * @return a pointer to the new hash map + */ +UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size); + +/** + * Frees a hash map. + * + * Note: the contents are not freed, use ucx_map_free_content() + * before calling this function to achieve that. + * + * @param map the map to be freed + * @see ucx_map_free_content() + */ +void ucx_map_free(UcxMap *map); + +/** + * Frees the contents of a hash map. + * + * This is a convenience function that iterates over the map and passes all + * values to the specified destructor function. + * + * If no destructor is specified (NULL), the free() function of + * the map's own allocator is used. + * + * You must ensure, that it is valid to pass each value in the map to the same + * destructor function. + * + * You should free or clear the map afterwards, as the contents will be invalid. + * + * @param map for which the contents shall be freed + * @param destr optional pointer to a destructor function + * @see ucx_map_free() + * @see ucx_map_clear() + */ +void ucx_map_free_content(UcxMap *map, ucx_destructor destr); + +/** + * Clears a hash map. + * + * Note: the contents are not freed, use ucx_map_free_content() + * before calling this function to achieve that. + * + * @param map the map to be cleared + * @see ucx_map_free_content() + */ +void ucx_map_clear(UcxMap *map); + + +/** + * Copies contents from a map to another map using a copy function. + * + * Note: The destination map does not need to be empty. However, if it + * contains data with keys that are also present in the source map, the contents + * are overwritten. + * + * @param from the source map + * @param to the destination map + * @param fnc the copy function or NULL if the pointer address + * shall be copied + * @param data additional data for the copy function + * @return 0 on success or a non-zero value on memory allocation errors + */ +int ucx_map_copy(UcxMap *from, UcxMap *to, 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 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(UcxMap *map, copy_func fnc, void *data); + +/** + * Increases size of the hash map, if necessary. + * + * The load value is 0.75*UcxMap.size. If the element count exceeds the load + * value, the map needs to be rehashed. Otherwise no action is performed and + * this function simply returns 0. + * + * The rehashing process ensures, that the UcxMap.size is at least + * 2.5*UcxMap.count. So there is enough room for additional elements without + * the need of another soon rehashing. + * + * You can use this function to dramatically increase access performance. + * + * @param map the map to rehash + * @return 1, if a memory allocation error occurred, 0 otherwise + */ +int ucx_map_rehash(UcxMap *map); + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +int ucx_map_put(UcxMap *map, UcxKey key, void *value); + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +void* ucx_map_get(UcxMap *map, UcxKey key); + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + * @return the removed value + */ +void* ucx_map_remove(UcxMap *map, UcxKey key); + +/** + * 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 + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_sstr_put(map, key, value) \ + ucx_map_put(map, ucx_key(key.ptr, key.length), (void*)value) + +/** + * Shorthand for putting data with a C string key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_cstr_put(map, key, value) \ + ucx_map_put(map, ucx_key(key, strlen(key)), (void*)value) + +/** + * Shorthand for putting data with an integer key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_int_put(map, key, value) \ + ucx_map_put(map, ucx_key(&key, sizeof(key)), (void*)value) + +/** + * Shorthand for getting data from the map with a sstr_t key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_sstr_get(map, key) \ + ucx_map_get(map, ucx_key(key.ptr, key.length)) + +/** + * Shorthand for getting data from the map with a C string key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_cstr_get(map, key) \ + ucx_map_get(map, ucx_key(key, strlen(key))) + +/** + * Shorthand for getting data from the map with an integer key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_int_get(map, key) \ + ucx_map_get(map, ucx_key(&key, sizeof(int))) + +/** + * Shorthand for removing data from the map with a sstr_t key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_sstr_remove(map, key) \ + ucx_map_remove(map, ucx_key(key.ptr, key.length)) + +/** + * Shorthand for removing data from the map with a C string key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_cstr_remove(map, key) \ + ucx_map_remove(map, ucx_key(key, strlen(key))) + +/** + * Shorthand for removing data from the map with an integer key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_int_remove(map, key) \ + ucx_map_remove(map, ucx_key(&key, sizeof(key))) + +/** + * Creates a UcxKey based on the given data. + * + * This function implicitly computes the hash. + * + * @param data the data for the key + * @param len the length of the data + * @return a UcxKey with implicitly computed hash + * @see ucx_hash() + */ +UcxKey ucx_key(const void *data, size_t len); + +/** + * Computes a murmur hash-2. + * + * @param data the data to hash + * @param len the length of the data + * @return the murmur hash-2 of the data + */ +int ucx_hash(const char *data, size_t len); + +/** + * Creates an iterator for a map. + * + * Note: A UcxMapIterator iterates over all elements in all element + * lists successively. Therefore the order highly depends on the key hashes and + * may vary under different map sizes. So generally you may NOT rely on + * the iteration order. + * + * Note: The iterator is NOT initialized. You need to call + * ucx_map_iter_next() at least once before accessing any information. However, + * it is not recommended to access the fields of a UcxMapIterator directly. + * + * @param map the map to create the iterator for + * @return an iterator initialized on the first element of the + * first element list + * @see ucx_map_iter_next() + */ +UcxMapIterator ucx_map_iterator(UcxMap *map); + +/** + * Proceeds to the next element of the map (if any). + * + * Subsequent calls on the same iterator proceed to the next element and + * store the key/value-pair into the memory specified as arguments of this + * function. + * + * If no further elements are found, this function returns zero and leaves the + * last found key/value-pair in memory. + * + * @param iterator the iterator to use + * @param key a pointer to the memory where to store the key + * @param value a pointer to the memory where to store the value + * @return 1, if another element was found, 0 if all elements has been processed + * @see ucx_map_iterator() + */ +int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value); + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_MAP_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/mempool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/mempool.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,209 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file mempool.h + * + * Memory pool implementation. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_MEMPOOL_H +#define UCX_MEMPOOL_H + +#include "ucx.h" +#include "allocator.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX mempool structure. + */ +typedef struct { + /** UcxAllocator based on this pool */ + UcxAllocator *allocator; + + /** List of pointers to pooled memory. */ + void **data; + + /** Count of pooled memory items. */ + size_t ndata; + + /** Memory pool size. */ + size_t size; +} UcxMempool; + +/** Shorthand for a new default memory pool with a capacity of 16 elements. */ +#define ucx_mempool_new_default() ucx_mempool_new(16) + + +/** + * Creates a memory pool with the specified initial size. + * + * As the created memory pool automatically grows in size by factor two when + * trying to allocate memory on a full pool, it is recommended that you use + * a power of two for the initial size. + * + * @param n initial pool size (should be a power of two, e.g. 16) + * @return a pointer to the new memory pool + * @see ucx_mempool_new_default() + */ +UcxMempool *ucx_mempool_new(size_t n); + +/** + * Resizes a memory pool. + * + * This function will fail if the new capacity is not sufficient for the + * present data. + * + * @param pool the pool to resize + * @param newcap the new capacity + * @return zero on success or non-zero on failure + */ +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); + +/** + * Allocates pooled memory. + * + * @param pool the memory pool + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_allocator_malloc() + */ +void *ucx_mempool_malloc(UcxMempool *pool, size_t n); +/** + * Allocates a pooled memory array. + * + * The content of the allocated memory is set to zero. + * + * @param pool the memory pool + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_allocator_calloc() + */ +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize); + +/** + * Reallocates pooled memory. + * + * If the memory to be reallocated is not contained by the specified pool, the + * behavior is undefined. + * + * @param pool the memory pool + * @param ptr a pointer to the memory that shall be reallocated + * @param n the new size of the memory + * @return a pointer to the new location of the memory + * @see ucx_allocator_realloc() + */ +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); + +/** + * Frees pooled memory. + * + * Before freeing the memory, the specified destructor function (if any) + * is called. + * + * If you specify memory, that is not pooled by the specified memory pool, the + * program will terminate with a call to abort(). + * + * @param pool the memory pool + * @param ptr a pointer to the memory that shall be freed + * @see ucx_mempool_set_destr() + */ +void ucx_mempool_free(UcxMempool *pool, void *ptr); + +/** + * Destroys a memory pool. + * + * For each element the destructor function (if any) is called and the element + * is freed. + * + * Each of the registered destructor function that has no corresponding element + * within the pool (namely those registered by ucx_mempool_reg_destr) is + * called interleaving with the element destruction, but with guarantee to the + * order in which they were registered (FIFO order). + * + * + * @param pool the mempool to destroy + */ +void ucx_mempool_destroy(UcxMempool *pool); + +/** + * Sets a destructor function for the specified memory. + * + * The destructor is automatically called when the memory is freed or the + * pool is destroyed. + * A destructor for pooled memory MUST NOT free the memory itself, + * as this is done by the pool. Use a destructor to free any resources + * managed by the pooled object. + * + * The only requirement for the specified memory is, that it MUST be + * pooled memory by a UcxMempool or an element-compatible mempool. The pointer + * to the destructor function is saved in a reserved area before the actual + * memory. + * + * @param ptr pooled memory + * @param func a pointer to the destructor function + * @see ucx_mempool_free() + * @see ucx_mempool_destroy() + */ +void ucx_mempool_set_destr(void *ptr, ucx_destructor func); + +/** + * Registers a destructor function for the specified (non-pooled) memory. + * + * This is useful, if you have memory that has not been allocated by a mempool, + * but shall be managed by a mempool. + * + * This function creates an entry in the specified mempool and the memory will + * therefore (logically) convert to pooled memory. + * However, this does not cause the memory to be freed automatically!. + * If you want to use this function, make the memory pool free non-pooled + * memory, the specified destructor function must call free() + * by itself. But keep in mind, that you then MUST NOT use this destructor + * function with pooled memory (e.g. in ucx_mempool_set_destr()), as it + * would cause a double-free. + * + * @param pool the memory pool + * @param ptr data the destructor is registered for + * @param destr a pointer to the destructor function + */ +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_MEMPOOL_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/properties.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/properties.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,221 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * @file properties.h + * + * Load / store utilities for properties files. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_PROPERTIES_H +#define UCX_PROPERTIES_H + +#include "ucx.h" +#include "map.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UcxProperties object for parsing properties data. + * Most of the fields are for internal use only. You may configure the + * properties parser, e.g. by changing the used delimiter or specifying + * up to three different characters that shall introduce comments. + */ +typedef struct { + /** + * Input buffer (don't set manually). + * Automatically set by calls to ucx_properties_fill(). + */ + char *buffer; + + /** + * Length of the input buffer (don't set manually). + * Automatically set by calls to ucx_properties_fill(). + */ + size_t buflen; + + /** + * Current buffer position (don't set manually). + * Used by ucx_properties_next(). + */ + size_t pos; + + /** + * Internal temporary buffer (don't set manually). + * Used by ucx_properties_next(). + */ + char *tmp; + + /** + * Internal temporary buffer length (don't set manually). + * Used by ucx_properties_next(). + */ + size_t tmplen; + + /** + * Internal temporary buffer capacity (don't set manually). + * Used by ucx_properties_next(). + */ + size_t tmpcap; + + /** + * Parser error code. + * This is always 0 on success and a nonzero value on syntax errors. + * The value is set by ucx_properties_next(). + */ + int error; + + /** + * The delimiter that shall be used. + * This is '=' by default. + */ + char delimiter; + + /** + * The first comment character. + * This is '#' by default. + */ + char comment1; + + /** + * The second comment character. + * This is not set by default. + */ + char comment2; + + /** + * The third comment character. + * This is not set by default. + */ + char comment3; +} UcxProperties; + + +/** + * Constructs a new UcxProperties object. + * @return a pointer to the new UcxProperties object + */ +UcxProperties *ucx_properties_new(); + +/** + * Destroys a UcxProperties object. + * @param prop the UcxProperties object to destroy + */ +void ucx_properties_free(UcxProperties *prop); + +/** + * Sets the input buffer for the properties parser. + * + * After calling this function, you may parse the data by calling + * ucx_properties_next() until it returns 0. The function ucx_properties2map() + * is a convenience function that reads as much data as possible by using this + * function. + * + * + * @param prop the UcxProperties object + * @param buf a pointer to the new buffer + * @param len the payload length of the buffer + * @see ucx_properties_next() + * @see ucx_properties2map() + */ +void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len); + +/** + * Retrieves the next key/value-pair. + * + * This function returns a nonzero value as long as there are key/value-pairs + * found. If no more key/value-pairs are found, you may refill the input buffer + * with ucx_properties_fill(). + * + * Attention: the sstr_t.ptr pointers of the output parameters point to + * memory within the input buffer of the parser and will get invalid some time. + * If you want long term copies of the key/value-pairs, use sstrdup() after + * calling this function. + * + * @param prop the UcxProperties object + * @param name a pointer to the sstr_t that shall contain the property name + * @param value a pointer to the sstr_t that shall contain the property value + * @return Nonzero, if a key/value-pair was successfully retrieved + * @see ucx_properties_fill() + */ +int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value); + +/** + * Retrieves all available key/value-pairs and puts them into a UcxMap. + * + * This is done by successive calls to ucx_properties_next() until no more + * key/value-pairs can be retrieved. + * + * The memory for the map values is allocated by the map's own allocator. + * + * @param prop the UcxProperties object + * @param map the target map + * @return The UcxProperties.error code (i.e. 0 on success). + * @see ucx_properties_fill() + * @see UcxMap.allocator + */ +int ucx_properties2map(UcxProperties *prop, UcxMap *map); + +/** + * Loads a properties file to a UcxMap. + * + * This is a convenience function that reads data from an input + * stream until the end of the stream is reached. + * + * @param map the map object to write the key/value-pairs to + * @param file the FILE* stream to read from + * @return 0 on success, or a non-zero value on error + * + * @see ucx_properties_fill() + * @see ucx_properties2map() + */ +int ucx_properties_load(UcxMap *map, FILE *file); + +/** + * Stores a UcxMap to a file. + * + * The key/value-pairs are written by using the following format: + * + * [key] = [value]\\n + * + * @param map the map to store + * @param file the FILE* stream to write to + * @return 0 on success, or a non-zero value on error + */ +int ucx_properties_store(UcxMap *map, FILE *file); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_PROPERTIES_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/stack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/stack.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,240 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file stack.h + * + * Default stack memory allocation implementation. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_STACK_H +#define UCX_STACK_H + +#include "ucx.h" +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * UCX stack structure. + */ +typedef struct { + /** UcxAllocator based on this stack */ + UcxAllocator allocator; + + /** Stack size. */ + size_t size; + + /** Pointer to the bottom of the stack */ + char *space; + + /** Pointer to the top of the stack */ + char *top; +} UcxStack; + +/** + * Metadata for each UCX stack element. + */ +struct ucx_stack_metadata { + /** + * Location of the previous element (NULL if this is the first) + */ + char *prev; + + /** Size of this element */ + size_t size; +}; + +/** + * Initializes UcxStack structure with memory. + * + * @param stack a pointer to an uninitialized stack structure + * @param space the memory area that shall be managed + * @param size size of the memory area + * @return a new UcxStack structure + */ +void ucx_stack_init(UcxStack *stack, char* space, size_t size); + +/** + * Allocates stack memory. + * + * @param stack a pointer to the stack + * @param n amount of memory to allocate + * @return a pointer to the allocated memory or NULL on stack + * overflow + * @see ucx_allocator_malloc() + */ +void *ucx_stack_malloc(UcxStack *stack, size_t n); + +/** + * Allocates memory with #ucx_stack_malloc() and copies the specified data if + * the allocation was successful. + * + * @param stack a pointer to the stack + * @param n amount of memory to allocate + * @param data a pointer to the data to copy + * @return a pointer to the allocated memory + * @see ucx_stack_malloc + */ +void *ucx_stack_push(UcxStack *stack, size_t n, const void *data); + +/** + * Allocates an array of stack memory + * + * The content of the allocated memory is set to zero. + * + * @param stack a pointer to the stack + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_allocator_calloc() + */ +void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize); + +/** + * Allocates memory with #ucx_stack_calloc() and copies the specified data if + * the allocation was successful. + * + * @param stack a pointer to the stack + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @param data a pointer to the data + * @return a pointer to the allocated memory + * @see ucx_stack_calloc + */ +void *ucx_stack_pusharr(UcxStack *stack, + size_t nelem, size_t elsize, const void *data); + +/** + * Reallocates memory on the stack. + * + * Shrinking memory is always safe. Extending memory can be very expensive. + * + * @param stack the stack + * @param ptr a pointer to the memory that shall be reallocated + * @param n the new size of the memory + * @return a pointer to the new location of the memory + * @see ucx_allocator_realloc() + */ +void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n); + +/** + * Frees memory on the stack. + * + * Freeing stack memory behaves in a special way. + * + * If the element, that should be freed, is the top most element of the stack, + * it is removed from the stack. Otherwise it is marked as freed. Marked + * elements are removed, when they become the top most elements of the stack. + * + * @param stack a pointer to the stack + * @param ptr a pointer to the memory that shall be freed + */ +void ucx_stack_free(UcxStack *stack, void *ptr); + + +/** + * Returns the size of the top most element. + * @param stack a pointer to the stack + * @return the size of the top most element + */ +#define ucx_stack_topsize(stack) ((stack)->top ? ((struct ucx_stack_metadata*)\ + (stack)->top - 1)->size : 0) + +/** + * Removes the top most element from the stack and copies the content to + * dest, if specified. + * + * Use #ucx_stack_topsize()# to get the amount of memory that must be available + * at the location of dest. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to, or + * NULL, if the element shall only be removed. + * @see ucx_stack_free + * @see ucx_stack_popn + */ +#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, (size_t)-1) + +/** + * Removes the top most element from the stack and copies the content to + * dest. + * + * This function copies at most n bytes to the destination, but + * the element is always freed as a whole. + * If the element was larger than n, the remaining data is lost. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to + * @param n copies at most n bytes to dest + * @see ucx_stack_pop + */ +void ucx_stack_popn(UcxStack *stack, void *dest, size_t n); + +/** + * Returns the remaining available memory on the specified stack. + * + * @param stack a pointer to the stack + * @return the remaining available memory + */ +size_t ucx_stack_avail(UcxStack *stack); + +/** + * Checks, if the stack is empty. + * + * @param stack a pointer to the stack + * @return nonzero, if the stack is empty, zero otherwise + */ +#define ucx_stack_empty(stack) (!(stack)->top) + +/** + * Computes a recommended size for the stack memory area. Note, that + * reallocations have not been taken into account, so you might need to reserve + * twice as much memory to allow many reallocations. + * + * @param size the approximate payload + * @param elems the approximate count of element allocations + * @return a recommended size for the stack space based on the information + * provided + */ +#define ucx_stack_dim(size, elems) (size+sizeof(struct ucx_stack_metadata) * \ + (elems + 1)) + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_STACK_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/string.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/string.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,1079 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Bounded string implementation. + * + * The UCX strings (sstr_t) provide an alternative to C strings. + * The main difference to C strings is, that sstr_t does not + * need to be NULL-terminated. Instead the length is stored + * within the structure. + * + * When using sstr_t, developers must be full aware of what type + * of string (NULL-terminated) or not) they are using, when + * accessing the char* ptr directly. + * + * The UCX string module provides some common string functions, known from + * standard libc, working with sstr_t. + * + * @file string.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_STRING_H +#define UCX_STRING_H + +#include "ucx.h" +#include "allocator.h" +#include + +/* + * Use this macro to disable the shortcuts if you experience macro collision. + */ +#ifndef UCX_NO_SSTR_SHORTCUTS +/** + * Shortcut for a sstr_t struct + * or scstr_t struct literal. + */ +#define ST(s) { s, sizeof(s)-1 } + +/** Shortcut for the conversion of a C string to a sstr_t. */ +#define S(s) sstrn(s, sizeof(s)-1) + +/** Shortcut for the conversion of a C string to a scstr_t. */ +#define SC(s) scstrn(s, sizeof(s)-1) +#endif /* UCX_NO_SSTR_SHORTCUTS */ + +/* + * Use this macro to disable the format macros. + */ +#ifndef UCX_NO_SSTR_FORMAT_MACROS +/** Expands a sstr_t or scstr_t to printf arguments. */ +#define SFMT(s) (int) (s).length, (s).ptr + +/** Format specifier for a sstr_t or scstr_t. */ +#define PRIsstr ".*s" +#endif /* UCX_NO_SSTR_FORMAT_MACROS */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The UCX string structure. + */ +typedef struct { + /** A pointer to the string + * (not necessarily NULL-terminated) */ + char *ptr; + /** The length of the string */ + size_t length; +} sstr_t; + +/** + * The UCX string structure for immutable (constant) strings. + */ +typedef struct { + /** A constant pointer to the immutable string + * (not necessarily NULL-terminated) */ + const char *ptr; + /** The length of the string */ + size_t length; +} scstr_t; + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +/** + * One of two type adjustment functions that return an scstr_t. + * + * Used internally to convert a UCX string to an immutable UCX string. + * + * Do not use this function manually. + * + * @param str some sstr_t + * @return an immutable (scstr_t) version of the provided string. + */ +inline scstr_t s2scstr(sstr_t s) { + scstr_t c; + c.ptr = s.ptr; + c.length = s.length; + return c; +} + +/** + * One of two type adjustment functions that return an scstr_t. + * + * Used internally to convert a UCX string to an immutable UCX string. + * This variant is used, when the string is already immutable and no operation + * needs to be performed. + * + * Do not use this function manually. + * + * @param str some scstr_t + * @return the argument itself + */ +inline scstr_t s2scstr(scstr_t str) { + return str; +} + +/** + * Converts a UCX string to an immutable UCX string (scstr_t). + * @param str some UCX string + * @return an immutable version of the provided string + */ +#define SCSTR(s) s2scstr(s) +#else + +/** + * One of two type adjustment functions that return an scstr_t. + * + * Used internally to convert a UCX string to an immutable UCX string. + * This variant is used, when the string is already immutable and no operation + * needs to be performed. + * + * Do not use this function manually. + * + * @param str some scstr_t + * @return the argument itself + */ +scstr_t ucx_sc2sc(scstr_t str); + +/** + * One of two type adjustment functions that return an scstr_t. + * + * Used internally to convert a UCX string to an immutable UCX string. + * + * Do not use this function manually. + * + * @param str some sstr_t + * @return an immutable (scstr_t) version of the provided string. + */ +scstr_t ucx_ss2sc(sstr_t str); + +#if __STDC_VERSION__ >= 201112L +/** + * Converts a UCX string to an immutable UCX string (scstr_t). + * @param str some UCX string + * @return an immutable version of the provided string + */ +#define SCSTR(str) _Generic(str, sstr_t: ucx_ss2sc, scstr_t: ucx_sc2sc)(str) + +#elif defined(__GNUC__) || defined(__clang__) + +/** + * Converts a UCX string to an immutable UCX string (scstr_t). + * @param str some UCX string + * @return an immutable version of the provided string + */ +#define SCSTR(str) __builtin_choose_expr( \ + __builtin_types_compatible_p(typeof(str), sstr_t), \ + ucx_ss2sc, \ + ucx_sc2sc)(str) + +#elif defined(__sun) + +/** + * Converts a UCX string to an immutable UCX string (scstr_t). + * @param str some UCX string + * @return the an immutable version of the provided string + */ +#define SCSTR(str) ({typeof(str) ucx_tmp_var_str = str; \ + scstr_t ucx_tmp_var_c; \ + ucx_tmp_var_c.ptr = ucx_tmp_var_str.ptr;\ + ucx_tmp_var_c.length = ucx_tmp_var_str.length;\ + ucx_tmp_var_c; }) +#else /* no generics and no builtins */ + +/** + * Converts a UCX string to an immutable UCX string (scstr_t). + * + * This internal function (ab)uses the C standard an expects one single + * argument which is then implicitly converted to scstr_t without a warning. + * + * Do not use this function manually. + * + * @return the an immutable version of the provided string + */ +scstr_t ucx_ss2c_s(); + +/** + * Converts a UCX string to an immutable UCX string (scstr_t). + * @param str some UCX string + * @return the an immutable version of the provided string + */ +#define SCSTR(str) ucx_ss2c_s(str) +#endif /* C11 feature test */ + +#endif /* C++ */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Creates a new sstr_t based on a C string. + * + * The length is implicitly inferred by using a call to strlen(). + * + * Note: the sstr_t will share the specified pointer to the C string. + * If you do want a copy, use sstrdup() on the return value of this function. + * + * If you need to wrap a constant string, use scstr(). + * + * @param cstring the C string to wrap + * @return a new sstr_t containing the C string + * + * @see sstrn() + */ +sstr_t sstr(char *cstring); + +/** + * Creates a new sstr_t of the specified length based on a C string. + * + * Note: the sstr_t will share the specified pointer to the C string. + * If you do want a copy, use sstrdup() on the return value of this function. + * + * If you need to wrap a constant string, use scstrn(). + * + * @param cstring the C string to wrap + * @param length the length of the string + * @return a new sstr_t containing the C string + * + * @see sstr() + * @see S() + */ +sstr_t sstrn(char *cstring, size_t length); + +/** + * Creates a new scstr_t based on a constant C string. + * + * The length is implicitly inferred by using a call to strlen(). + * + * Note: the scstr_t will share the specified pointer to the C string. + * If you do want a copy, use scstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @return a new scstr_t containing the C string + * + * @see scstrn() + */ +scstr_t scstr(const char *cstring); + + +/** + * Creates a new scstr_t of the specified length based on a constant C string. + * + * Note: the scstr_t will share the specified pointer to the C string. + * If you do want a copy, use scstrdup() on the return value of this function. * + * + * @param cstring the C string to wrap + * @param length the length of the string + * @return a new scstr_t containing the C string + * + * @see scstr() + */ +scstr_t scstrn(const char *cstring, size_t length); + +/** + * Returns the accumulated length of all specified strings. + * + * Attention: if the count argument is larger than the count of the + * specified strings, the behavior is undefined. + * + * @param count the total number of specified strings + * @param ... all strings + * @return the accumulated length of all strings + */ +size_t scstrnlen(size_t count, ...); + +/** + * Returns the accumulated length of all specified strings. + * + * Attention: if the count argument is larger than the count of the + * specified strings, the behavior is undefined. + * + * @param count the total number of specified strings + * @param ... all strings + * @return the cumulated length of all strings + */ +#define sstrnlen(count, ...) scstrnlen(count, __VA_ARGS__) + +/** + * Concatenates two or more strings. + * + * The resulting string will be allocated by standard malloc(). + * So developers MUST pass the sstr_t.ptr to free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param count the total number of strings to concatenate + * @param s1 first string + * @param ... all remaining strings + * @return the concatenated string + */ +sstr_t scstrcat(size_t count, scstr_t s1, ...); + +/** + * Concatenates two or more strings. + * + * The resulting string will be allocated by standard malloc(). + * So developers MUST pass the sstr_t.ptr to free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param count the total number of strings to concatenate + * @param s1 first string + * @param ... all remaining strings + * @return the concatenated string + */ +#define sstrcat(count, s1, ...) scstrcat(count, SCSTR(s1), __VA_ARGS__) + +/** + * Concatenates two or more strings using a UcxAllocator. + * + * The resulting string must be freed by the allocators free() + * implementation. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param alloc the allocator to use + * @param count the total number of strings to concatenate + * @param s1 first string + * @param ... all remaining strings + * @return the concatenated string + * + * @see scstrcat() + */ +sstr_t scstrcat_a(UcxAllocator *alloc, size_t count, scstr_t s1, ...); + +/** + * Concatenates two or more strings using a UcxAllocator. + * + * The resulting string must be freed by the allocators free() + * implementation. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param alloc the allocator to use + * @param count the total number of strings to concatenate + * @param s1 first string + * @param ... all remaining strings + * @return the concatenated string + * + * @see sstrcat() + */ +#define sstrcat_a(alloc, count, s1, ...) \ + scstrcat_a(alloc, count, SCSTR(s1), __VA_ARGS__) + +/** + * Returns a substring starting at the specified location. + * + * Attention: the new string references the same memory area as the + * input string and is NOT required to be NULL-terminated. + * Use sstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @return a substring of string starting at start + * + * @see sstrsubsl() + * @see sstrchr() + */ +sstr_t sstrsubs(sstr_t string, size_t start); + +/** + * Returns a substring with the given length starting at the specified location. + * + * Attention: the new string references the same memory area as the + * input string and is NOT required to be NULL-terminated. + * Use sstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @param length the maximum length of the substring + * @return a substring of string starting at start + * with a maximum length of length + * + * @see sstrsubs() + * @see sstrchr() + */ +sstr_t sstrsubsl(sstr_t string, size_t start, size_t length); + +/** + * Returns a substring of an immutable string starting at the specified + * location. + * + * Attention: the new string references the same memory area as the +* input string and is NOT required to be NULL-terminated. + * Use scstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @return a substring of string starting at start + * + * @see scstrsubsl() + * @see scstrchr() + */ +scstr_t scstrsubs(scstr_t string, size_t start); + +/** + * Returns a substring of an immutable string with a maximum length starting + * at the specified location. + * + * Attention: the new string references the same memory area as the + * input string and is NOT required to be NULL-terminated. + * Use scstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @param length the maximum length of the substring + * @return a substring of string starting at start + * with a maximum length of length + * + * @see scstrsubs() + * @see scstrchr() + */ +scstr_t scstrsubsl(scstr_t string, size_t start, size_t length); + +/** + * Returns a substring starting at the location of the first occurrence of the + * specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the first location of chr + * + * @see sstrsubs() + */ +sstr_t sstrchr(sstr_t string, int chr); + +/** + * Returns a substring starting at the location of the last occurrence of the + * specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the last location of chr + * + * @see sstrsubs() + */ +sstr_t sstrrchr(sstr_t string, int chr); + +/** + * Returns an immutable substring starting at the location of the first + * occurrence of the specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the first location of chr + * + * @see scstrsubs() + */ +scstr_t scstrchr(scstr_t string, int chr); + +/** + * Returns an immutable substring starting at the location of the last + * occurrence of the specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the last location of chr + * + * @see scstrsubs() + */ +scstr_t scstrrchr(scstr_t string, int chr); + +/** + * Returns a substring starting at the location of the first occurrence of the + * specified string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. + * + * @param string the string to be scanned + * @param match string containing the sequence of characters to match + * @return a substring starting at the first occurrence of + * match, or an empty string, if the sequence is not + * present in string + */ +sstr_t scstrsstr(sstr_t string, scstr_t match); + +/** + * Returns a substring starting at the location of the first occurrence of the + * specified string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. + * + * @param string the string to be scanned + * @param match string containing the sequence of characters to match + * @return a substring starting at the first occurrence of + * match, or an empty string, if the sequence is not + * present in string + */ +#define sstrstr(string, match) scstrsstr(string, SCSTR(match)) + +/** + * Returns an immutable substring starting at the location of the + * first occurrence of the specified immutable string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. + * + * @param string the string to be scanned + * @param match string containing the sequence of characters to match + * @return a substring starting at the first occurrence of + * match, or an empty string, if the sequence is not + * present in string + */ +scstr_t scstrscstr(scstr_t string, scstr_t match); + +/** + * Returns an immutable substring starting at the location of the + * first occurrence of the specified immutable string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. + * + * @param string the string to be scanned + * @param match string containing the sequence of characters to match + * @return a substring starting at the first occurrence of + * match, or an empty string, if the sequence is not + * present in string + */ +#define sstrscstr(string, match) scstrscstr(string, SCSTR(match)) + +/** + * Splits a string into parts by using a delimiter string. + * + * This function will return NULL, if one of the following happens: + *
    + *
  • the string length is zero
  • + *
  • the delimeter length is zero
  • + *
  • the string equals the delimeter
  • + *
  • memory allocation fails
  • + *
+ * + * The integer referenced by count is used as input and determines + * the maximum size of the resulting array, i.e. the maximum count of splits to + * perform + 1. + * + * The integer referenced by count is also used as output and is + * set to + *
    + *
  • -2, on memory allocation errors
  • + *
  • -1, if either the string or the delimiter is an empty string
  • + *
  • 0, if the string equals the delimiter
  • + *
  • 1, if the string does not contain the delimiter
  • + *
  • the count of array items, otherwise
  • + *
+ * + * If the string starts with the delimiter, the first item of the resulting + * array will be an empty string. + * + * If the string ends with the delimiter and the maximum list size is not + * exceeded, the last array item will be an empty string. + * In case the list size would be exceeded, the last array item will be the + * remaining string after the last split, including the terminating + * delimiter. + * + * Attention: The array pointer AND all sstr_t.ptr of the array + * items must be manually passed to free(). Use scstrsplit_a() with + * an allocator to managed memory, to avoid this. + * + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * NULL on error + * + * @see scstrsplit_a() + */ +sstr_t* scstrsplit(scstr_t string, scstr_t delim, ssize_t *count); + +/** + * Splits a string into parts by using a delimiter string. + * + * This function will return NULL, if one of the following happens: + *
    + *
  • the string length is zero
  • + *
  • the delimeter length is zero
  • + *
  • the string equals the delimeter
  • + *
  • memory allocation fails
  • + *
+ * + * The integer referenced by count is used as input and determines + * the maximum size of the resulting array, i.e. the maximum count of splits to + * perform + 1. + * + * The integer referenced by count is also used as output and is + * set to + *
    + *
  • -2, on memory allocation errors
  • + *
  • -1, if either the string or the delimiter is an empty string
  • + *
  • 0, if the string equals the delimiter
  • + *
  • 1, if the string does not contain the delimiter
  • + *
  • the count of array items, otherwise
  • + *
+ * + * If the string starts with the delimiter, the first item of the resulting + * array will be an empty string. + * + * If the string ends with the delimiter and the maximum list size is not + * exceeded, the last array item will be an empty string. + * In case the list size would be exceeded, the last array item will be the + * remaining string after the last split, including the terminating + * delimiter. + * + * Attention: The array pointer AND all sstr_t.ptr of the array + * items must be manually passed to free(). Use sstrsplit_a() with + * an allocator to managed memory, to avoid this. + * + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * NULL on error + * + * @see sstrsplit_a() + */ +#define sstrsplit(string, delim, count) \ + scstrsplit(SCSTR(string), SCSTR(delim), count) + +/** + * Performing scstrsplit() using a UcxAllocator. + * + * Read the description of scstrsplit() for details. + * + * The memory for the sstr_t.ptr pointers of the array items and the memory for + * the sstr_t array itself are allocated by using the UcxAllocator.malloc() + * function. + * + * @param allocator the UcxAllocator used for allocating memory + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * NULL on error + * + * @see scstrsplit() + */ +sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t string, scstr_t delim, + ssize_t *count); + +/** + * Performing sstrsplit() using a UcxAllocator. + * + * Read the description of sstrsplit() for details. + * + * The memory for the sstr_t.ptr pointers of the array items and the memory for + * the sstr_t array itself are allocated by using the UcxAllocator.malloc() + * function. + * + * @param allocator the UcxAllocator used for allocating memory + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * NULL on error + * + * @see sstrsplit() + */ +#define sstrsplit_a(allocator, string, delim, count) \ + scstrsplit_a(allocator, SCSTR(string), SCSTR(delim), count) + +/** + * Compares two UCX strings with standard memcmp(). + * + * At first it compares the scstr_t.length attribute of the two strings. The + * memcmp() function is called, if and only if the lengths match. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of + * memcmp() otherwise (i.e. 0 if the strings match) + */ +int scstrcmp(scstr_t s1, scstr_t s2); + +/** + * Compares two UCX strings with standard memcmp(). + * + * At first it compares the sstr_t.length attribute of the two strings. The + * memcmp() function is called, if and only if the lengths match. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of + * memcmp() otherwise (i.e. 0 if the strings match) + */ +#define sstrcmp(s1, s2) scstrcmp(SCSTR(s1), SCSTR(s2)) + +/** + * Compares two UCX strings ignoring the case. + * + * At first it compares the scstr_t.length attribute of the two strings. If and + * only if the lengths match, both strings are compared char by char ignoring + * the case. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of the platform + * specific string comparison function ignoring the case. + */ +int scstrcasecmp(scstr_t s1, scstr_t s2); + +/** + * Compares two UCX strings ignoring the case. + * + * At first it compares the sstr_t.length attribute of the two strings. If and + * only if the lengths match, both strings are compared char by char ignoring + * the case. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of the platform + * specific string comparison function ignoring the case. + */ +#define sstrcasecmp(s1, s2) scstrcasecmp(SCSTR(s1), SCSTR(s2)) + +/** + * Creates a duplicate of the specified string. + * + * The new sstr_t will contain a copy allocated by standard + * malloc(). So developers MUST pass the sstr_t.ptr to + * free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated and mutable, regardless of the argument. + * + * @param string the string to duplicate + * @return a duplicate of the string + * @see scstrdup_a() + */ +sstr_t scstrdup(scstr_t string); + +/** + * Creates a duplicate of the specified string. + * + * The new sstr_t will contain a copy allocated by standard + * malloc(). So developers MUST pass the sstr_t.ptr to + * free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated, regardless of the argument. + * + * @param string the string to duplicate + * @return a duplicate of the string + * @see sstrdup_a() + */ +#define sstrdup(string) scstrdup(SCSTR(string)) + +/** + * Creates a duplicate of the specified string using a UcxAllocator. + * + * The new sstr_t will contain a copy allocated by the allocators + * UcxAllocator.malloc() function. So it is implementation depended, whether the + * returned sstr_t.ptr pointer must be passed to the allocators + * UcxAllocator.free() function manually. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated and mutable, regardless of the argument. + * + * @param allocator a valid instance of a UcxAllocator + * @param string the string to duplicate + * @return a duplicate of the string + * @see scstrdup() + */ +sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t string); + +/** + * Creates a duplicate of the specified string using a UcxAllocator. + * + * The new sstr_t will contain a copy allocated by the allocators + * UcxAllocator.malloc() function. So it is implementation depended, whether the + * returned sstr_t.ptr pointer must be passed to the allocators + * UcxAllocator.free() function manually. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated, regardless of the argument. + * + * @param allocator a valid instance of a UcxAllocator + * @param string the string to duplicate + * @return a duplicate of the string + * @see scstrdup() + */ +#define sstrdup_a(allocator, string) scstrdup_a(allocator, SCSTR(string)) + + +/** + * Omits leading and trailing spaces. + * + * This function returns a new sstr_t containing a trimmed version of the + * specified string. + * + * Note: the new sstr_t references the same memory, thus you + * MUST NOT pass the sstr_t.ptr of the return value to + * free(). It is also highly recommended to avoid assignments like + * mystr = sstrtrim(mystr); as you lose the reference to the + * source string. Assignments of this type are only permitted, if the + * sstr_t.ptr of the source string does not need to be freed or if another + * reference to the source string exists. + * + * @param string the string that shall be trimmed + * @return a new sstr_t containing the trimmed string + */ +sstr_t sstrtrim(sstr_t string); + +/** + * Omits leading and trailing spaces. + * + * This function returns a new scstr_t containing a trimmed version of the + * specified string. + * + * Note: the new scstr_t references the same memory, thus you + * MUST NOT pass the scstr_t.ptr of the return value to + * free(). It is also highly recommended to avoid assignments like + * mystr = scstrtrim(mystr); as you lose the reference to the + * source string. Assignments of this type are only permitted, if the + * scstr_t.ptr of the source string does not need to be freed or if another + * reference to the source string exists. + * + * @param string the string that shall be trimmed + * @return a new scstr_t containing the trimmed string + */ +scstr_t scstrtrim(scstr_t string); + +/** + * Checks, if a string has a specific prefix. + * + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +int scstrprefix(scstr_t string, scstr_t prefix); + +/** + * Checks, if a string has a specific prefix. + * + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +#define sstrprefix(string, prefix) scstrprefix(SCSTR(string), SCSTR(prefix)) + +/** + * Checks, if a string has a specific suffix. + * + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +int scstrsuffix(scstr_t string, scstr_t suffix); + +/** + * Checks, if a string has a specific suffix. + * + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +#define sstrsuffix(string, suffix) scstrsuffix(SCSTR(string), SCSTR(suffix)) + +/** + * Checks, if a string has a specific prefix, ignoring the case. + * + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +int scstrcaseprefix(scstr_t string, scstr_t prefix); + +/** + * Checks, if a string has a specific prefix, ignoring the case. + * + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +#define sstrcaseprefix(string, prefix) \ + scstrcaseprefix(SCSTR(string), SCSTR(prefix)) + +/** + * Checks, if a string has a specific suffix, ignoring the case. + * + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +int scstrcasesuffix(scstr_t string, scstr_t suffix); + +/** + * Checks, if a string has a specific suffix, ignoring the case. + * + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +#define sstrcasesuffix(string, suffix) \ + scstrcasesuffix(SCSTR(string), SCSTR(suffix)) + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first + * (see scstrdup()). + * + * @param string the input string + * @return the resulting lower case string + * @see scstrdup() + */ +sstr_t scstrlower(scstr_t string); + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup()). + * + * @param string the input string + * @return the resulting lower case string + */ +#define sstrlower(string) scstrlower(SCSTR(string)) + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first + * (see scstrdup_a()). + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting lower case string + * @see scstrdup_a() + */ +sstr_t scstrlower_a(UcxAllocator *allocator, scstr_t string); + + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup_a()). + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting lower case string + */ +#define sstrlower_a(allocator, string) scstrlower_a(allocator, SCSTR(string)) + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first + * (see scstrdup()). + * + * @param string the input string + * @return the resulting upper case string + * @see scstrdup() + */ +sstr_t scstrupper(scstr_t string); + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup()). + * + * @param string the input string + * @return the resulting upper case string + */ +#define sstrupper(string) scstrupper(SCSTR(string)) + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first + * (see scstrdup_a()). + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting upper case string + * @see scstrdup_a() + */ +sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string); + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup_a()). + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting upper case string + */ +#define sstrupper_a(allocator, string) scstrupper_a(allocator, string) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_STRING_H */ diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/test.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,241 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file: test.h + * + * UCX Test Framework. + * + * Usage of this test framework: + * + * **** IN HEADER FILE: **** + * + *
+ * UCX_TEST(function_name);
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist); // optional
+ * 
+ * + * **** IN SOURCE FILE: **** + *
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) {
+ *   // tests with UCX_TEST_ASSERT()
+ * }
+ * 
+ * UCX_TEST(function_name) {
+ *   // memory allocation and other stuff here
+ *   #UCX_TEST_BEGIN
+ *   // tests with UCX_TEST_ASSERT() and/or
+ *   // calls with UCX_TEST_CALL_SUBROUTINE() here
+ *   #UCX_TEST_END
+ *   // cleanup of memory here
+ * }
+ * 
+ * + * Note: if a test fails, a longjump is performed + * back to the #UCX_TEST_BEGIN macro! + * + * Attention: Do not call own functions within a test, that use + * UCX_TEST_ASSERT() macros and are not defined by using UCX_TEST_SUBROUTINE(). + * + * + * @author Mike Becker + * @author Olaf Wintermann + * + */ + +#ifndef UCX_TEST_H +#define UCX_TEST_H + +#include "ucx.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __FUNCTION__ + +/** + * Alias for the __func__ preprocessor macro. + * Some compilers use __func__ and others use __FUNCTION__. + * We use __FUNCTION__ so we define it for those compilers which use + * __func__. + */ +#define __FUNCTION__ __func__ +#endif + +/** Type for the UcxTestSuite. */ +typedef struct UcxTestSuite UcxTestSuite; + +/** Pointer to a test function. */ +typedef void(*UcxTest)(UcxTestSuite*,FILE*); + +/** Type for the internal list of test cases. */ +typedef struct UcxTestList UcxTestList; + +/** Structure for the internal list of test cases. */ +struct UcxTestList { + + /** Test case. */ + UcxTest test; + + /** Pointer to the next list element. */ + UcxTestList *next; +}; + +/** + * A test suite containing multiple test cases. + */ +struct UcxTestSuite { + + /** The number of successful tests after the suite has been run. */ + unsigned int success; + + /** The number of failed tests after the suite has been run. */ + unsigned int failure; + + /** + * Internal list of test cases. + * Use ucx_test_register() to add tests to this list. + */ + UcxTestList *tests; +}; + +/** + * Creates a new test suite. + * @return a new test suite + */ +UcxTestSuite* ucx_test_suite_new(); + +/** + * Destroys a test suite. + * @param suite the test suite to destroy + */ +void ucx_test_suite_free(UcxTestSuite* suite); + +/** + * Registers a test function with the specified test suite. + * + * @param suite the suite, the test function shall be added to + * @param test the test function to register + * @return EXIT_SUCCESS on success or + * EXIT_FAILURE on failure + */ +int ucx_test_register(UcxTestSuite* suite, UcxTest test); + +/** + * Runs a test suite and writes the test log to the specified stream. + * @param suite the test suite to run + * @param outstream the stream the log shall be written to + */ +void ucx_test_run(UcxTestSuite* suite, FILE* outstream); + +/** + * Macro for a #UcxTest function header. + * + * Use this macro to declare and/or define a #UcxTest function. + * + * @param name the name of the test function + */ +#define UCX_TEST(name) void name(UcxTestSuite* _suite_,FILE *_output_) + +/** + * Marks the begin of a test. + * Note: Any UCX_TEST_ASSERT() calls must be performed after + * #UCX_TEST_BEGIN. + * + * @see #UCX_TEST_END + */ +#define UCX_TEST_BEGIN fwrite("Running ", 1, 8, _output_);\ + fwrite(__FUNCTION__, 1, strlen(__FUNCTION__), _output_);\ + fwrite("... ", 1, 4, _output_);\ + jmp_buf _env_; \ + if (!setjmp(_env_)) { + +/** + * Checks a test assertion. + * If the assertion is correct, the test carries on. If the assertion is not + * correct, the specified message (terminated by a dot and a line break) is + * written to the test suites output stream. + * @param condition the condition to check + * @param message the message that shall be printed out on failure + */ +#define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \ + fwrite(message".\n", 1, 2+strlen(message), _output_); \ + _suite_->failure++; \ + longjmp(_env_, 1);\ + } + +/** + * Macro for a test subroutine function header. + * + * Use this to declare and/or define a subroutine that can be called by using + * UCX_TEST_CALL_SUBROUTINE(). + * + * @param name the name of the subroutine + * @param ... the parameter list + * + * @see UCX_TEST_CALL_SUBROUTINE() + */ +#define UCX_TEST_SUBROUTINE(name,...) void name(UcxTestSuite* _suite_,\ + FILE *_output_, jmp_buf _env_, __VA_ARGS__) + +/** + * Macro for calling a test subroutine. + * + * Subroutines declared with UCX_TEST_SUBROUTINE() can be called by using this + * macro. + * + * Note: You may only call subroutines within a #UCX_TEST_BEGIN- + * #UCX_TEST_END-block. + * + * @param name the name of the subroutine + * @param ... the argument list + * + * @see UCX_TEST_SUBROUTINE() + */ +#define UCX_TEST_CALL_SUBROUTINE(name,...) \ + name(_suite_,_output_,_env_,__VA_ARGS__); + +/** + * Marks the end of a test. + * Note: Any UCX_TEST_ASSERT() calls must be performed before + * #UCX_TEST_END. + * + * @see #UCX_TEST_BEGIN + */ +#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;} + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_TEST_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/ucx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/ucx.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,195 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Main UCX Header providing most common definitions. + * + * @file ucx.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_H +#define UCX_H + +/** Major UCX version as integer constant. */ +#define UCX_VERSION_MAJOR 2 + +/** Minor UCX version as integer constant. */ +#define UCX_VERSION_MINOR 1 + +/** Version constant which ensures to increase monotonically. */ +#define UCX_VERSION (((UCX_VERSION_MAJOR)<<16)|UCX_VERSION_MINOR) + +#include +#include + +#ifdef _WIN32 +#if !(defined __ssize_t_defined || defined _SSIZE_T_) +#include +typedef SSIZE_T ssize_t; +#define __ssize_t_defined +#define _SSIZE_T_ +#endif /* __ssize_t_defined and _SSIZE_T */ +#else /* !_WIN32 */ +#include +#endif /* _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * A function pointer to a destructor function. + * @see ucx_mempool_setdestr() + * @see ucx_mempool_regdestr() + */ +typedef void(*ucx_destructor)(void*); + +/** + * Function pointer to a compare function. + * + * The compare function shall take three arguments: the two values that shall be + * compared and optional additional data. + * The function shall then return -1 if the first argument is less than the + * second argument, 1 if the first argument is greater than the second argument + * and 0 if both arguments are equal. If the third argument is + * NULL, it shall be ignored. + */ +typedef int(*cmp_func)(const void*,const void*,void*); + +/** + * Function pointer to a distance function. + * + * The distance function shall take three arguments: the two values for which + * the distance shall be computed and optional additional data. + * The function shall then return the signed distance as integer value. + */ +typedef intmax_t(*distance_func)(const void*,const void*,void*); + +/** + * Function pointer to a copy function. + * + * The copy function shall create a copy of the first argument and may use + * additional data provided by the second argument. If the second argument is + * NULL, it shall be ignored. + + * Attention: if pointers returned by functions of this type may be + * passed to free() depends on the implementation of the + * respective copy_func. + */ +typedef void*(*copy_func)(const void*,void*); + +/** + * Function pointer to a write function. + * + * The signature of the write function shall be compatible to the signature + * of standard fwrite, though it may use arbitrary data types for + * source and destination. + * + * The arguments shall contain (in ascending order): a pointer to the source, + * the length of one element, the element count and a pointer to the + * destination. + */ +typedef size_t(*write_func)(const void*, size_t, size_t, void*); + +/** + * Function pointer to a read function. + * + * The signature of the read function shall be compatible to the signature + * of standard fread, though it may use arbitrary data types for + * source and destination. + * + * The arguments shall contain (in ascending order): a pointer to the + * destination, the length of one element, the element count and a pointer to + * the source. + */ +typedef size_t(*read_func)(void*, size_t, size_t, void*); + + + +#if __GNUC__ >= 5 || defined(__clang__) +#define UCX_MUL_BUILTIN + +#if __WORDSIZE == 32 +/** + * Alias for __builtin_umul_overflow. + * + * Performs a multiplication of size_t values and checks for overflow. + * + * @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 + */ +#define ucx_szmul(a, b, result) __builtin_umul_overflow(a, b, result) +#else /* __WORDSIZE != 32 */ +/** + * Alias for __builtin_umull_overflow. + * + * Performs a multiplication of size_t values and checks for overflow. + * + * @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 + */ +#define ucx_szmul(a, b, result) __builtin_umull_overflow(a, b, result) +#endif /* __WORDSIZE */ + +#else /* no GNUC or clang bultin */ + +/** + * 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 + */ +#define ucx_szmul(a, b, result) ucx_szmul_impl(a, b, result) + +int ucx_szmul_impl(size_t a, size_t b, size_t *result); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/ucx/utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx/utils.h Tue Aug 25 12:07:56 2020 +0200 @@ -0,0 +1,508 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file utils.h + * + * Compare, copy and printf functions. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_UTILS_H +#define UCX_UTILS_H + +#include "ucx.h" +#include "string.h" +#include "allocator.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy(). + */ +#define UCX_STREAM_COPY_BUFSIZE 4096 + +/** + * Copies a string. + * @param s the string to copy + * @param data omitted + * @return a pointer to a copy of s1 that can be passed to free(void*) + */ +void *ucx_strcpy(const void *s, void *data); + +/** + * Copies a memory area. + * @param m a pointer to the memory area + * @param n a pointer to the size_t containing the size of the memory area + * @return a pointer to a copy of the specified memory area that can + * be passed to free(void*) + */ +void *ucx_memcpy(const void *m, void *n); + + +/** + * Reads data from a stream and writes it to another stream. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or NULL if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if NULL was + * provided for buf, this is the size of the buffer that shall be + * implicitly created + * @param n the maximum number of bytes that shall be copied + * @return the total number of bytes copied + */ +size_t ucx_stream_bncopy(void *src, void *dest, read_func rfnc, write_func wfnc, + char* buf, size_t bufsize, size_t n); + +/** + * Shorthand for an unbounded ucx_stream_bncopy call using a default buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @return total number of bytes copied + * + * @see #UCX_STREAM_COPY_BUFSIZE + */ +#define ucx_stream_copy(src,dest,rfnc,wfnc) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + NULL, UCX_STREAM_COPY_BUFSIZE, (size_t)-1) + +/** + * Shorthand for ucx_stream_bncopy using a default copy buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param n maximum number of bytes that shall be copied + * @return total number of bytes copied + */ +#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + NULL, UCX_STREAM_COPY_BUFSIZE, n) + +/** + * Shorthand for an unbounded ucx_stream_bncopy call using the specified buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or NULL if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if NULL was + * provided for buf, this is the size of the buffer that shall be + * implicitly created + * @return total number of bytes copied + */ +#define ucx_stream_bcopy(src,dest,rfnc,wfnc, buf, bufsize) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + buf, bufsize, (size_t)-1) + +/** + * Wraps the strcmp function. + * @param s1 string one + * @param s2 string two + * @param data omitted + * @return the result of strcmp(s1, s2) + */ +int ucx_cmp_str(const void *s1, const void *s2, void *data); + +/** + * Wraps the strncmp function. + * @param s1 string one + * @param s2 string two + * @param n a pointer to the size_t containing the third strncmp parameter + * @return the result of strncmp(s1, s2, *n) + */ +int ucx_cmp_strn(const void *s1, const void *s2, void *n); + +/** + * Wraps the sstrcmp function. + * @param s1 sstr one + * @param s2 sstr two + * @param data ignored + * @return the result of sstrcmp(s1, s2) + */ +int ucx_cmp_sstr(const void *s1, const void *s2, void *data); + +/** + * Compares two integers of type int. + * @param i1 pointer to integer one + * @param i2 pointer to integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type long int. + * @param i1 pointer to long integer one + * @param i2 pointer to long integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_longint(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type long long. + * @param i1 pointer to long long one + * @param i2 pointer to long long two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_longlong(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type int16_t. + * @param i1 pointer to int16_t one + * @param i2 pointer to int16_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int16(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type int32_t. + * @param i1 pointer to int32_t one + * @param i2 pointer to int32_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int32(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type int64_t. + * @param i1 pointer to int64_t one + * @param i2 pointer to int64_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int64(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type unsigned int. + * @param i1 pointer to unsigned integer one + * @param i2 pointer to unsigned integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type unsigned long int. + * @param i1 pointer to unsigned long integer one + * @param i2 pointer to unsigned long integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_ulongint(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type unsigned long long. + * @param i1 pointer to unsigned long long one + * @param i2 pointer to unsigned long long two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_ulonglong(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type uint16_t. + * @param i1 pointer to uint16_t one + * @param i2 pointer to uint16_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint16(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type uint32_t. + * @param i1 pointer to uint32_t one + * @param i2 pointer to uint32_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint32(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type uint64_t. + * @param i1 pointer to uint64_t one + * @param i2 pointer to uint64_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint64(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int. + * @param i1 pointer to integer one + * @param i2 pointer to integer two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type long int. + * @param i1 pointer to long integer one + * @param i2 pointer to long integer two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_longint(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type long long. + * @param i1 pointer to long long one + * @param i2 pointer to long long two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_longlong(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int16_t. + * @param i1 pointer to int16_t one + * @param i2 pointer to int16_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int16(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int32_t. + * @param i1 pointer to int32_t one + * @param i2 pointer to int32_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int32(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int64_t. + * @param i1 pointer to int64_t one + * @param i2 pointer to int64_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int64(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type unsigned int. + * @param i1 pointer to unsigned integer one + * @param i2 pointer to unsigned integer two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type unsigned long int. + * @param i1 pointer to unsigned long integer one + * @param i2 pointer to unsigned long integer two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_ulongint(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type unsigned long long. + * @param i1 pointer to unsigned long long one + * @param i2 pointer to unsigned long long two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_ulonglong(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type uint16_t. + * @param i1 pointer to uint16_t one + * @param i2 pointer to uint16_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint16(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type uint32_t. + * @param i1 pointer to uint32_t one + * @param i2 pointer to uint32_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint32(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type uint64_t. + * @param i1 pointer to uint64_t one + * @param i2 pointer to uint64_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint64(const void *i1, const void *i2, void *data); + +/** + * Compares two real numbers of type float. + * @param f1 pointer to float one + * @param f2 pointer to float two + * @param data if provided: a pointer to precision (default: 1e-6f) + * @return -1, if *f1 is less than *f2, 0 if both are equal, + * 1 if *f1 is greater than *f2 + */ + +int ucx_cmp_float(const void *f1, const void *f2, void *data); + +/** + * Compares two real numbers of type double. + * @param d1 pointer to double one + * @param d2 pointer to double two + * @param data if provided: a pointer to precision (default: 1e-14) + * @return -1, if *d1 is less than *d2, 0 if both are equal, + * 1 if *d1 is greater than *d2 + */ +int ucx_cmp_double(const void *d1, const void *d2, void *data); + +/** + * Compares two pointers. + * @param ptr1 pointer one + * @param ptr2 pointer two + * @param data omitted + * @return -1 if ptr1 is less than ptr2, 0 if both are equal, + * 1 if ptr1 is greater than ptr2 + */ +int ucx_cmp_ptr(const void *ptr1, const void *ptr2, void *data); + +/** + * Compares two memory areas. + * @param ptr1 pointer one + * @param ptr2 pointer two + * @param n a pointer to the size_t containing the third parameter for memcmp + * @return the result of memcmp(ptr1, ptr2, *n) + */ +int ucx_cmp_mem(const void *ptr1, const void *ptr2, void *n); + +/** + * A printf() like function which writes the output to a stream by + * using a write_func(). + * @param stream the stream the data is written to + * @param wfc the write function + * @param fmt format string + * @param ... additional arguments + * @return the total number of bytes written + */ +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...); + +/** + * va_list version of ucx_fprintf(). + * @param stream the stream the data is written to + * @param wfc the write function + * @param fmt format string + * @param ap argument list + * @return the total number of bytes written + * @see ucx_fprintf() + */ +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap); + +/** + * A printf() like function which allocates space for a sstr_t + * the result is written to. + * + * Attention: The sstr_t data is allocated with the allocators + * ucx_allocator_malloc() function. So it is implementation dependent, if + * the returned sstr_t.ptr pointer must be passed to the allocators + * ucx_allocator_free() function manually. + * + * Note: The sstr_t.ptr of the return value will always be + * NULL-terminated. + * + * @param allocator the UcxAllocator used for allocating the result sstr_t + * @param fmt format string + * @param ... additional arguments + * @return a sstr_t containing the formatted string + */ +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); + +/** + * va_list version of ucx_asprintf(). + * + * @param allocator the UcxAllocator used for allocating the result sstr_t + * @param fmt format string + * @param ap argument list + * @return a sstr_t containing the formatted string + * @see ucx_asprintf() + */ +sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); + +/** Shortcut for ucx_asprintf() with default allocator. */ +#define ucx_sprintf(...) \ + ucx_asprintf(ucx_default_allocator(), __VA_ARGS__) + +/** + * A printf() like function which writes the output to a + * UcxBuffer. + * + * @param buffer the buffer the data is written to + * @param ... format string and additional arguments + * @return the total number of bytes written + * @see ucx_fprintf() + */ +#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \ + (write_func)ucx_buffer_write, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_UTILS_H */ + diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/utils.c --- a/src/ucx/utils.c Fri Jul 24 08:00:11 2020 +0200 +++ b/src/ucx/utils.c Tue Aug 25 12:07:56 2020 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Mike Becker, 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: @@ -26,22 +26,23 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "utils.h" +#include "ucx/utils.h" + #include #include #include #include /* COPY FUCNTIONS */ -void* ucx_strcpy(void* s, void* data) { - char *str = (char*) s; +void* ucx_strcpy(const void* s, void* data) { + const char *str = (const char*) s; size_t n = 1+strlen(str); char *cpy = (char*) malloc(n); memcpy(cpy, str, n); return cpy; } -void* ucx_memcpy(void* m, void* n) { +void* ucx_memcpy(const void* m, void* n) { size_t k = *((size_t*)n); void *cpy = malloc(k); memcpy(cpy, m, k); @@ -87,17 +88,103 @@ /* COMPARE FUNCTIONS */ -int ucx_strcmp(void *s1, void *s2, void *data) { - return strcmp((char*)s1, (char*)s2); +int ucx_cmp_str(const void *s1, const void *s2, void *data) { + return strcmp((const char*)s1, (const char*)s2); +} + +int ucx_cmp_strn(const void *s1, const void *s2, void *n) { + return strncmp((const char*)s1, (const char*)s2, *((size_t*) n)); +} + +int ucx_cmp_sstr(const void *s1, const void *s2, void *data) { + sstr_t a = *(const sstr_t*) s1; + sstr_t b = *(const sstr_t*) s2; + return sstrcmp(a, b); +} + +int ucx_cmp_int(const void *i1, const void *i2, void *data) { + int a = *((const int*) i1); + int b = *((const int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_longint(const void *i1, const void *i2, void *data) { + long int a = *((const long int*) i1); + long int b = *((const long int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_longlong(const void *i1, const void *i2, void *data) { + long long a = *((const long long*) i1); + long long b = *((const long long*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } } -int ucx_strncmp(void *s1, void *s2, void *n) { - return strncmp((char*)s1, (char*)s2, *((size_t*) n)); +int ucx_cmp_int16(const void *i1, const void *i2, void *data) { + int16_t a = *((const int16_t*) i1); + int16_t b = *((const int16_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_int32(const void *i1, const void *i2, void *data) { + int32_t a = *((const int32_t*) i1); + int32_t b = *((const int32_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } } -int ucx_intcmp(void *i1, void *i2, void *data) { - int a = *((int*) i1); - int b = *((int*) i2); +int ucx_cmp_int64(const void *i1, const void *i2, void *data) { + int64_t a = *((const int64_t*) i1); + int64_t b = *((const int64_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint(const void *i1, const void *i2, void *data) { + unsigned int a = *((const unsigned int*) i1); + unsigned int b = *((const unsigned int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_ulongint(const void *i1, const void *i2, void *data) { + unsigned long int a = *((const unsigned long int*) i1); + unsigned long int b = *((const unsigned long int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_ulonglong(const void *i1, const void *i2, void *data) { + unsigned long long a = *((const unsigned long long*) i1); + unsigned long long b = *((const unsigned long long*) i2); if (a == b) { return 0; } else { @@ -105,9 +192,111 @@ } } -int ucx_floatcmp(void *f1, void *f2, void *epsilon) { - float a = *((float*) f1); - float b = *((float*) f2); +int ucx_cmp_uint16(const void *i1, const void *i2, void *data) { + uint16_t a = *((const uint16_t*) i1); + uint16_t b = *((const uint16_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint32(const void *i1, const void *i2, void *data) { + uint32_t a = *((const uint32_t*) i1); + uint32_t b = *((const uint32_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint64(const void *i1, const void *i2, void *data) { + uint64_t a = *((const uint64_t*) i1); + uint64_t b = *((const uint64_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +intmax_t ucx_dist_int(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int*) i1); + intmax_t b = *((const int*) i2); + return a - b; +} + +intmax_t ucx_dist_longint(const void *i1, const void *i2, void *data) { + intmax_t a = *((const long int*) i1); + intmax_t b = *((const long int*) i2); + return a - b; +} + +intmax_t ucx_dist_longlong(const void *i1, const void *i2, void *data) { + intmax_t a = *((const long long*) i1); + intmax_t b = *((const long long*) i2); + return a - b; +} + +intmax_t ucx_dist_int16(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int16_t*) i1); + intmax_t b = *((const int16_t*) i2); + return a - b; +} + +intmax_t ucx_dist_int32(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int32_t*) i1); + intmax_t b = *((const int32_t*) i2); + return a - b; +} + +intmax_t ucx_dist_int64(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int64_t*) i1); + intmax_t b = *((const int64_t*) i2); + return a - b; +} + +intmax_t ucx_dist_uint(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const unsigned int*) i1); + uintmax_t b = *((const unsigned int*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_ulongint(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const unsigned long int*) i1); + uintmax_t b = *((const unsigned long int*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_ulonglong(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const unsigned long long*) i1); + uintmax_t b = *((const unsigned long long*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_uint16(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const uint16_t*) i1); + uintmax_t b = *((const uint16_t*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_uint32(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const uint32_t*) i1); + uintmax_t b = *((const uint32_t*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_uint64(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const uint64_t*) i1); + uintmax_t b = *((const uint64_t*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +int ucx_cmp_float(const void *f1, const void *f2, void *epsilon) { + float a = *((const float*) f1); + float b = *((const float*) f2); float e = !epsilon ? 1e-6f : *((float*)epsilon); if (fabsf(a - b) < e) { return 0; @@ -116,9 +305,9 @@ } } -int ucx_doublecmp(void *d1, void *d2, void *epsilon) { - double a = *((float*) d1); - double b = *((float*) d2); +int ucx_cmp_double(const void *d1, const void *d2, void *epsilon) { + double a = *((const double*) d1); + double b = *((const double*) d2); double e = !epsilon ? 1e-14 : *((double*)epsilon); if (fabs(a - b) < e) { return 0; @@ -127,9 +316,9 @@ } } -int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) { - intptr_t p1 = (intptr_t) ptr1; - intptr_t p2 = (intptr_t) ptr2; +int ucx_cmp_ptr(const void *ptr1, const void *ptr2, void *data) { + const intptr_t p1 = (const intptr_t) ptr1; + const intptr_t p2 = (const intptr_t) ptr2; if (p1 == p2) { return 0; } else { @@ -137,7 +326,7 @@ } } -int ucx_memcmp(void *ptr1, void *ptr2, void *n) { +int ucx_cmp_mem(const void *ptr1, const void *ptr2, void *n) { return memcmp(ptr1, ptr2, *((size_t*)n)); } diff -r 5653a9626cc0 -r 0b8692959d37 src/ucx/utils.h --- a/src/ucx/utils.h Fri Jul 24 08:00:11 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2016 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file utils.h - * - * Compare, copy and printf functions. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_UTILS_H -#define UCX_UTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ucx.h" -#include "string.h" -#include "allocator.h" -#include -#include -#include - -/** - * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy(). - */ -#define UCX_STREAM_COPY_BUFSIZE 4096 - -/** - * Copies a string. - * @param s the string to copy - * @param data omitted - * @return a pointer to a copy of s1 that can be passed to free(void*) - */ -void *ucx_strcpy(void *s, void *data); - -/** - * Copies a memory area. - * @param m a pointer to the memory area - * @param n a pointer to the size_t containing the size of the memory area - * @return a pointer to a copy of the specified memory area that can - * be passed to free(void*) - */ -void *ucx_memcpy(void *m, void *n); - - -/** - * Reads data from a stream and writes it to another stream. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param buf a pointer to the copy buffer or NULL if a buffer - * shall be implicitly created on the heap - * @param bufsize the size of the copy buffer - if NULL was - * provided for buf, this is the size of the buffer that shall be - * implicitly created - * @param n the maximum number of bytes that shall be copied - * @return the total number of bytes copied - */ -size_t ucx_stream_bncopy(void *src, void *dest, read_func rfnc, write_func wfnc, - char* buf, size_t bufsize, size_t n); - -/** - * Shorthand for an unbounded ucx_stream_bncopy call using a default buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @return total number of bytes copied - * - * @see #UCX_STREAM_COPY_BUFSIZE - */ -#define ucx_stream_copy(src,dest,rfnc,wfnc) ucx_stream_bncopy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, \ - NULL, UCX_STREAM_COPY_BUFSIZE, (size_t)-1) - -/** - * Shorthand for ucx_stream_bncopy using a default copy buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param n maximum number of bytes that shall be copied - * @return total number of bytes copied - */ -#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_bncopy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, \ - NULL, UCX_STREAM_COPY_BUFSIZE, n) - -/** - * Shorthand for an unbounded ucx_stream_bncopy call using the specified buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param buf a pointer to the copy buffer or NULL if a buffer - * shall be implicitly created on the heap - * @param bufsize the size of the copy buffer - if NULL was - * provided for buf, this is the size of the buffer that shall be - * implicitly created - * @return total number of bytes copied - */ -#define ucx_stream_bcopy(src,dest,rfnc,wfnc, buf, bufsize) ucx_stream_bncopy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, \ - buf, bufsize, (size_t)-1) - -/** - * Wraps the strcmp function. - * @param s1 string one - * @param s2 string two - * @param data omitted - * @return the result of strcmp(s1, s2) - */ -int ucx_strcmp(void *s1, void *s2, void *data); - -/** - * Wraps the strncmp function. - * @param s1 string one - * @param s2 string two - * @param n a pointer to the size_t containing the third strncmp parameter - * @return the result of strncmp(s1, s2, *n) - */ -int ucx_strncmp(void *s1, void *s2, void *n); - -/** - * Compares two integers of type int. - * @param i1 pointer to integer one - * @param i2 pointer to integer two - * @param data omitted - * @return -1, if *i1 is less than *i2, 0 if both are equal, - * 1 if *i1 is greater than *i2 - */ -int ucx_intcmp(void *i1, void *i2, void *data); - -/** - * Compares two real numbers of type float. - * @param f1 pointer to float one - * @param f2 pointer to float two - * @param data if provided: a pointer to precision (default: 1e-6f) - * @return -1, if *f1 is less than *f2, 0 if both are equal, - * 1 if *f1 is greater than *f2 - */ - -int ucx_floatcmp(void *f1, void *f2, void *data); - -/** - * Compares two real numbers of type double. - * @param d1 pointer to double one - * @param d2 pointer to double two - * @param data if provided: a pointer to precision (default: 1e-14) - * @return -1, if *d1 is less than *d2, 0 if both are equal, - * 1 if *d1 is greater than *d2 - */ -int ucx_doublecmp(void *d1, void *d2, void *data); - -/** - * Compares two pointers. - * @param ptr1 pointer one - * @param ptr2 pointer two - * @param data omitted - * @return -1 if ptr1 is less than ptr2, 0 if both are equal, - * 1 if ptr1 is greater than ptr2 - */ -int ucx_ptrcmp(void *ptr1, void *ptr2, void *data); - -/** - * Compares two memory areas. - * @param ptr1 pointer one - * @param ptr2 pointer two - * @param n a pointer to the size_t containing the third parameter for memcmp - * @return the result of memcmp(ptr1, ptr2, *n) - */ -int ucx_memcmp(void *ptr1, void *ptr2, void *n); - -/** - * A printf() like function which writes the output to a stream by - * using a write_func(). - * @param stream the stream the data is written to - * @param wfc the write function - * @param fmt format string - * @param ... additional arguments - * @return the total number of bytes written - */ -int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...); - -/** - * va_list version of ucx_fprintf(). - * @param stream the stream the data is written to - * @param wfc the write function - * @param fmt format string - * @param ap argument list - * @return the total number of bytes written - * @see ucx_fprintf() - */ -int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap); - -/** - * A printf() like function which allocates space for a sstr_t - * the result is written to. - * - * Attention: The sstr_t data is allocated with the allocators - * ucx_allocator_malloc() function. So it is implementation dependent, if - * the returned sstr_t.ptr pointer must be passed to the allocators - * ucx_allocator_free() function manually. - * - * Note: The sstr_t.ptr of the return value will always be - * NULL-terminated. - * - * @param allocator the UcxAllocator used for allocating the result sstr_t - * @param fmt format string - * @param ... additional arguments - * @return a sstr_t containing the formatted string - */ -sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); - -/** - * va_list version of ucx_asprintf(). - * - * @param allocator the UcxAllocator used for allocating the result sstr_t - * @param fmt format string - * @param ap argument list - * @return a sstr_t containing the formatted string - * @see ucx_asprintf() - */ -sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); - -/** Shortcut for ucx_asprintf() with default allocator. */ -#define ucx_sprintf(...) \ - ucx_asprintf(ucx_default_allocator(), __VA_ARGS__) - -/** - * A printf() like function which writes the output to a - * UcxBuffer. - * - * @param buffer the buffer the data is written to - * @param ... format string and additional arguments - * @return the total number of bytes written - * @see ucx_fprintf() - */ -#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \ - (write_func)ucx_buffer_write, __VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_UTILS_H */ - diff -r 5653a9626cc0 -r 0b8692959d37 templates/config/server.template --- a/templates/config/server.template Fri Jul 24 08:00:11 2020 +0200 +++ b/templates/config/server.template Tue Aug 25 12:07:56 2020 +0200 @@ -2,46 +2,54 @@ # server.conf # - +Runtime +{ Temp /tmp/webserver-rw6pgl8b/ User webservd MimeFile mime.types - +} - +LogFile +{ File logs/errors Level INFO - +} - +AccessLog +{ File logs/access - +} - +EventHandler +{ Name default Threads 1 Default true - +} - +Threadpool +{ Name default MinThreads 4 MaxThreads 32 - +} - +Listener +{ Name http-listener-1 Port 9090 DefaultVS %%WS_HOST%% - +} - +Listener +{ Name http-listener-2 Port 9091 DefaultVS %%WS_HOST%% - +} - +VirtualServer +{ Name %%WS_HOST%% Host %%WS_HOST%% Listener http-listener-1 @@ -50,6 +58,9 @@ ACLFile acl.conf DAVFile dav.conf DocRoot docs/ - +} + + +