# HG changeset patch # User Olaf Wintermann # Date 1549297068 -3600 # Node ID 481802342fdf03a073f199f8c5f68ffb45ed273e # Parent bf3695fee719610996bcf659b1f7ee57e569ccba ucx update diff -r bf3695fee719 -r 481802342fdf dav/sync.c --- a/dav/sync.c Mon Feb 04 14:11:57 2019 +0100 +++ b/dav/sync.c Mon Feb 04 17:17:48 2019 +0100 @@ -3142,8 +3142,7 @@ UcxMapIterator iter = scfg_directory_iterator(); SyncDirectory *dir; UCX_MAP_FOREACH(key, dir, iter) { - reponames = ucx_list_append_once(reponames, - dir->repository, ucx_strcmp, NULL); + reponames = ucx_list_append(reponames, dir->repository); } } diff -r bf3695fee719 -r 481802342fdf libidav/crypto.c --- a/libidav/crypto.c Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/crypto.c Mon Feb 04 17:17:48 2019 +0100 @@ -257,7 +257,7 @@ } -char* aes_encrypt(char *in, size_t len, DavKey *key) { +char* aes_encrypt(const char *in, size_t len, DavKey *key) { unsigned char iv[16]; if(!RAND_bytes(iv, 16)) { return NULL; @@ -304,7 +304,7 @@ return out; } -char* aes_decrypt(char *in, size_t *length, DavKey *key) { +char* aes_decrypt(const char *in, size_t *length, DavKey *key) { int len; unsigned char *buf = (unsigned char*)util_base64decode_len(in, &len); @@ -660,7 +660,7 @@ free(enc); } -char* aes_encrypt(char *in, size_t len, DavKey *key) { +char* aes_encrypt(const char *in, size_t len, DavKey *key) { unsigned char iv[16]; if(dav_rand_bytes(iv, 16)) { return NULL; @@ -715,7 +715,7 @@ return b64enc; } -char* aes_decrypt(char *in, size_t *len, DavKey *key) { +char* aes_decrypt(const char *in, size_t *len, DavKey *key) { int inlen; unsigned char *buf = (unsigned char*)util_base64decode_len(in, &inlen); diff -r bf3695fee719 -r 481802342fdf libidav/crypto.h --- a/libidav/crypto.h Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/crypto.h Mon Feb 04 17:17:48 2019 +0100 @@ -109,8 +109,8 @@ void aes_encrypter_close(AESEncrypter *enc); int aes_encrypter_reset(AESEncrypter *enc, curl_off_t offset, int origin); -char* aes_encrypt(char *in, size_t len, DavKey *key); -char* aes_decrypt(char *in, size_t *len, DavKey *key); +char* aes_encrypt(const char *in, size_t len, DavKey *key); +char* aes_decrypt(const char *in, size_t *len, DavKey *key); void dav_get_hash(DAV_SHA_CTX *sha256, unsigned char *buf); diff -r bf3695fee719 -r 481802342fdf libidav/davqlexec.c --- a/libidav/davqlexec.c Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/davqlexec.c Mon Feb 04 17:17:48 2019 +0100 @@ -311,49 +311,57 @@ // add basic properties char *value; - UcxKey cl_key = dav_property_key("DAV:", "getcontentlength"); + sstr_t cl_keystr = dav_property_key("DAV:", "getcontentlength"); + UcxKey cl_key = ucx_key(cl_keystr.ptr, cl_keystr.length); value = ucx_map_get(data->properties, cl_key); if(value) { ucx_map_put(new_properties, cl_key, value); } - UcxKey cd_key = dav_property_key("DAV:", "creationdate"); + sstr_t cd_keystr = dav_property_key("DAV:", "creationdate"); + UcxKey cd_key = ucx_key(cd_keystr.ptr, cd_keystr.length); value = ucx_map_get(data->properties, cd_key); if(value) { ucx_map_put(new_properties, cd_key, value); } - UcxKey lm_key = dav_property_key("DAV:", "getlastmodified"); + sstr_t lm_keystr = dav_property_key("DAV:", "getlastmodified"); + UcxKey lm_key = ucx_key(lm_keystr.ptr, lm_keystr.length); value = ucx_map_get(data->properties, lm_key); if(value) { ucx_map_put(new_properties, lm_key, value); } - UcxKey ct_key = dav_property_key("DAV:", "getcontenttype"); + sstr_t ct_keystr = dav_property_key("DAV:", "getcontenttype"); + UcxKey ct_key = ucx_key(ct_keystr.ptr, ct_keystr.length); value = ucx_map_get(data->properties, ct_key); if(value) { ucx_map_put(new_properties, ct_key, value); } - UcxKey rt_key = dav_property_key("DAV:", "resourcetype"); + sstr_t rt_keystr = dav_property_key("DAV:", "resourcetype"); + UcxKey rt_key = ucx_key(rt_keystr.ptr, rt_keystr.length); value = ucx_map_get(data->properties, rt_key); if(value) { ucx_map_put(new_properties, rt_key, value); } - UcxKey cn_key = dav_property_key(DAV_NS, "crypto-name"); + sstr_t cn_keystr = dav_property_key(DAV_NS, "crypto-name"); + UcxKey cn_key = ucx_key(cn_keystr.ptr, cn_keystr.length); value = ucx_map_get(data->properties, cn_key); if(value) { ucx_map_put(new_properties, cn_key, value); } - UcxKey ck_key = dav_property_key(DAV_NS, "crypto-key"); + sstr_t ck_keystr = dav_property_key(DAV_NS, "crypto-key"); + UcxKey ck_key = ucx_key(ck_keystr.ptr, ck_keystr.length); value = ucx_map_get(data->properties, ck_key); if(value) { ucx_map_put(new_properties, ck_key, value); } - UcxKey ch_key = dav_property_key(DAV_NS, "crypto-hash"); + sstr_t ch_keystr = dav_property_key(DAV_NS, "crypto-hash"); + UcxKey ch_key = ucx_key(ch_keystr.ptr, ch_keystr.length); value = ucx_map_get(data->properties, ch_key); if(value) { ucx_map_put(new_properties, ch_key, value); @@ -395,9 +403,9 @@ node->contentlength = str.length; } if(node) { - UcxKey key = dav_property_key(field->ns, field->name); - ucx_map_put(new_properties, key, node); - free(key.data); + sstr_t key = dav_property_key(field->ns, field->name); + ucx_map_sstr_put(new_properties, key, node); + free(key.ptr); } } else { // TODO: error @@ -418,14 +426,14 @@ resource_free_properties(sn, data->properties); data->properties = new_properties; - free(cl_key.data); - free(cd_key.data); - free(lm_key.data); - free(ct_key.data); - free(rt_key.data); - free(cn_key.data); - free(ck_key.data); - free(ch_key.data); + free(cl_keystr.ptr); + free(cd_keystr.ptr); + free(lm_keystr.ptr); + free(ct_keystr.ptr); + free(rt_keystr.ptr); + free(cn_keystr.ptr); + free(ck_keystr.ptr); + free(ch_keystr.ptr); return 0; } @@ -534,7 +542,8 @@ if(ns && name) { DavOrderCriterion *cr = ucx_mempool_malloc(mp, sizeof(DavOrderCriterion)); cr->type = 1; - cr->column.property = dav_property_key_a(mp->allocator, ns, name); + sstr_t keystr = dav_property_key_a(mp->allocator, ns, name); + cr->column.property = ucx_key(keystr.ptr, keystr.length); cr->descending = oc->descending; ordercr = ucx_list_append_a(mp->allocator, ordercr, cr); } else { diff -r bf3695fee719 -r 481802342fdf libidav/methods.c --- a/libidav/methods.c Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/methods.c Mon Feb 04 17:17:48 2019 +0100 @@ -755,7 +755,7 @@ UcxBuffer* create_proppatch_request(DavResourceData *data) { UcxBuffer *buf = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND); - sstr_t s; + scstr_t s; UcxMap *namespaces = ucx_map_new(8); char prefix[8]; @@ -775,32 +775,32 @@ } } - s = S("\n"); + s = SC("\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); // write root element and namespaces - s = S("\n"); + s = SC(">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); if(data->set) { - s = S("\n\n"); + s = SC("\n\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); UCX_FOREACH(elm, data->set) { DavProperty *property = elm->data; @@ -810,15 +810,15 @@ } // begin tag - s = S("<"); + s = SC("<"); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prefix); + s = scstr(prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); + s = SC(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->name); + s = scstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(">"); + s = SC(">"); ucx_buffer_write(s.ptr, 1, s.length, buf); // content @@ -830,43 +830,43 @@ } // end tag - s = S("name); + s = scstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(">\n"); + s = SC(">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } - s = S("\n\n"); + s = SC("\n\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } if(data->remove) { - s = S("\n\n"); + s = SC("\n\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); UCX_FOREACH(elm, data->remove) { DavProperty *property = elm->data; char *prefix = ucx_map_cstr_get(namespaces, property->ns->name); - s = S("<"); + s = SC("<"); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prefix); + s = scstr(prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); + s = SC(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->name); + s = scstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(" />\n"); + s = SC(" />\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } - s = S("\n\n"); + s = SC("\n\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } - s = S("\n"); + s = SC("\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); // cleanup namespace map @@ -876,7 +876,7 @@ return buf; } -UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, char *name, char *hash) { +UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, const char *name, const char *hash) { UcxBuffer *buf = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND); sstr_t s; diff -r bf3695fee719 -r 481802342fdf libidav/methods.h --- a/libidav/methods.h Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/methods.h Mon Feb 04 17:17:48 2019 +0100 @@ -106,7 +106,7 @@ int parse_resource_type(xmlNode *node); UcxBuffer* create_proppatch_request(DavResourceData *data); -UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, char *name, char *hash); +UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, const char *name, const char *hash); CURLcode do_delete_request(DavSession *sn, char *lock, UcxBuffer *response); diff -r bf3695fee719 -r 481802342fdf libidav/resource.c --- a/libidav/resource.c Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/resource.c Mon Feb 04 17:17:48 2019 +0100 @@ -239,15 +239,15 @@ return resource->href; } -void resource_add_property(DavResource *res, char *ns, char *name, xmlNode *val) { +void resource_add_property(DavResource *res, const char *ns, const char *name, xmlNode *val) { if(!val) { return; } - UcxKey key = dav_property_key(ns, name); + sstr_t key = dav_property_key(ns, name); DavXmlNode *v = dav_convert_xml(res->session, val); - ucx_map_put(((DavResourceData*)res->data)->properties, key, v); - free(key.data); + ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v); + free(key.ptr); } void resource_add_string_property(DavResource *res, char *ns, char *name, char *val) { @@ -255,16 +255,17 @@ return; } - UcxKey key = dav_property_key(ns, name); + sstr_t key = dav_property_key(ns, name); DavXmlNode *v = dav_text_node(res->session, val); - ucx_map_put(((DavResourceData*)res->data)->properties, key, v); - free(key.data); + ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v); + free(key.ptr); } -DavXmlNode* resource_get_property(DavResource *res, char *ns, char *name) { - UcxKey key = dav_property_key(ns, name); +DavXmlNode* resource_get_property(DavResource *res, const char *ns, const char *name) { + sstr_t keystr = dav_property_key(ns, name); + UcxKey key = ucx_key(keystr.ptr, keystr.length); DavXmlNode *property = resource_get_property_k(res, key); - free(key.data); + free(keystr.ptr); return property; } @@ -273,18 +274,15 @@ return ucx_map_get(data->properties, key); } -UcxKey dav_property_key(char *ns, char *name) { +sstr_t dav_property_key(const char *ns, const char *name) { return dav_property_key_a(ucx_default_allocator(), ns, name); } -UcxKey dav_property_key_a(UcxAllocator *a, char *ns, char *name) { - sstr_t ns_str = sstr(ns); - sstr_t name_str = sstr(name); +sstr_t dav_property_key_a(UcxAllocator *a, const char *ns, const char *name) { + scstr_t ns_str = scstr(ns); + scstr_t name_str = scstr(name); - sstr_t key; - key = sstrcat_a(a, 4, ns_str, S("\0"), name_str, S("\0")); - - return ucx_key(key.ptr, key.length); + return sstrcat_a(a, 4, ns_str, S("\0"), name_str, S("\0")); } @@ -447,7 +445,7 @@ return dav_get_property_ns(res, pns, pname); } -DavXmlNode* dav_get_property_ns(DavResource *res, char *ns, char *name) { +DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name) { if(!ns || !name) { return NULL; } @@ -585,7 +583,7 @@ UCX_MAP_FOREACH(key, value, i) { DavPropName *name = &names[j]; // the map key is namespace + '\0' + name - name->ns = key.data; + name->ns = (char*)key.data; for(int k=0;jname = (char*)key.data + k + 1; @@ -1180,7 +1178,7 @@ } -int resource_add_crypto_info(DavSession *sn, char *href, char *name, char *hash) { +int resource_add_crypto_info(DavSession *sn, const char *href, const char *name, const char *hash) { if(!DAV_IS_ENCRYPTED(sn)) { return 0; } diff -r bf3695fee719 -r 481802342fdf libidav/resource.h --- a/libidav/resource.h Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/resource.h Mon Feb 04 17:17:48 2019 +0100 @@ -74,14 +74,14 @@ void resource_set_info(DavResource *res, char *href_str); DavResourceData* resource_data_new(DavSession *sn); -void resource_add_property(DavResource *res, char *ns, char *name, xmlNode *val); -DavXmlNode* resource_get_property(DavResource *res, char *ns, char *name); +void resource_add_property(DavResource *res, const char *ns, const char *name, xmlNode *val); +DavXmlNode* resource_get_property(DavResource *res, const char *ns, const char *name); DavXmlNode* resource_get_property_k(DavResource *res, UcxKey key); void resource_add_child(DavResource *parent, DavResource *child); void resource_add_ordered_child(DavResource *parent, DavResource *child, UcxList *ordercr); -int resource_add_crypto_info(DavSession *sn, char *href, char *name, char *hash); +int resource_add_crypto_info(DavSession *sn, const char *href, const char *name, const char *hash); -UcxKey dav_property_key_a(UcxAllocator *a, char *ns, char *name); +sstr_t dav_property_key_a(UcxAllocator *a, const char *ns, const char *name); #ifdef __cplusplus } diff -r bf3695fee719 -r 481802342fdf libidav/session.c --- a/libidav/session.c Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/session.c Mon Feb 04 17:17:48 2019 +0100 @@ -273,7 +273,7 @@ void dav_session_destroy(DavSession *sn) { // remove session from context UcxList *sessions = sn->context->sessions; - ssize_t i = ucx_list_find(sessions, sn, ucx_ptrcmp, NULL); + ssize_t i = ucx_list_find(sessions, sn, ucx_cmp_ptr, NULL); if(i >= 0) { UcxList *elm = ucx_list_get(sessions, i); if(elm) { diff -r bf3695fee719 -r 481802342fdf libidav/utils.c --- a/libidav/utils.c Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/utils.c Mon Feb 04 17:17:48 2019 +0100 @@ -387,9 +387,9 @@ return url.ptr; } -char* util_get_url(DavSession *sn, char *href) { - sstr_t base = sstr(sn->base_url); - sstr_t href_str = sstr(href); +char* util_get_url(DavSession *sn, const char *href) { + scstr_t base = scstr(sn->base_url); + scstr_t href_str = scstr(href); char *base_path = util_url_path(sn->base_url); base.length -= strlen(base_path); @@ -398,7 +398,7 @@ return url.ptr; } -void util_set_url(DavSession *sn, char *href) { +void util_set_url(DavSession *sn, const char *href) { char *url = util_get_url(sn, href); curl_easy_setopt(sn->handle, CURLOPT_URL, url); free(url); @@ -463,7 +463,7 @@ } -char* util_base64decode(char *in) { +char* util_base64decode(const char *in) { int len = 0; return util_base64decode_len(in, &len); } @@ -484,7 +484,7 @@ 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, 66,66,66,66,66,66 }; -char* util_base64decode_len(char* in, int *outlen) { +char* util_base64decode_len(const char* in, int *outlen) { /* code is mostly from wikibooks */ size_t inlen = strlen(in); @@ -494,7 +494,7 @@ unsigned char *out = (unsigned char*)outbuf; - char *end = in + inlen; + const char *end = in + inlen; char iter = 0; uint32_t buf = 0; size_t len = 0; @@ -559,7 +559,7 @@ static char* b64enctable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -char* util_base64encode(char *in, size_t len) { +char* util_base64encode(const char *in, size_t len) { // calculate length of base64 output and create buffer size_t outlen = 4 * ((len + 2) / 3); int pad = len % 3; diff -r bf3695fee719 -r 481802342fdf libidav/utils.h --- a/libidav/utils.h Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/utils.h Mon Feb 04 17:17:48 2019 +0100 @@ -69,8 +69,8 @@ char* util_url_decode(DavSession *sn, char *url); char* util_resource_name(char *url); char* util_concat_path(const char *url_base, const char *path); -char* util_get_url(DavSession *sn, char *href); -void util_set_url(DavSession *sn, char *href); +char* util_get_url(DavSession *sn, const char *href); +void util_set_url(DavSession *sn, const char *href); void util_capture_header(CURL *handle, UcxMap* map); @@ -82,9 +82,9 @@ char* util_xml_get_text(const xmlNode *elm); -char* util_base64decode(char *in); -char* util_base64decode_len(char *in, int *outlen); -char* util_base64encode(char *in, size_t len); +char* util_base64decode(const char *in); +char* util_base64decode_len(const char *in, int *outlen); +char* util_base64encode(const char *in, size_t len); char* util_encrypt_str(DavSession *sn, char *str, char *key); char* util_encrypt_str_k(DavSession *sn, char *str, DavKey *key); diff -r bf3695fee719 -r 481802342fdf libidav/webdav.h --- a/libidav/webdav.h Mon Feb 04 14:11:57 2019 +0100 +++ b/libidav/webdav.h Mon Feb 04 17:17:48 2019 +0100 @@ -249,7 +249,7 @@ DavResource* dav_query(DavSession *sn, char *query, ...); -UcxKey dav_property_key(char *ns, char *name); +sstr_t dav_property_key(const char *ns, const char *name); void dav_get_property_namespace_str( DavContext *ctx, char *prefixed_name, @@ -288,7 +288,7 @@ int dav_unlock(DavResource *res); DavXmlNode* dav_get_property(DavResource *res, char *name); -DavXmlNode* dav_get_property_ns(DavResource *res, char *ns, char *name); +DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name); char* dav_get_string_property(DavResource *res, char *name); char* dav_get_string_property_ns(DavResource *res, char *ns, char *name); void dav_set_string_property(DavResource *res, char *name, char *value); diff -r bf3695fee719 -r 481802342fdf ucx/allocator.c --- a/ucx/allocator.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/allocator.c Mon Feb 04 17:17:48 2019 +0100 @@ -30,7 +30,7 @@ #include -UcxAllocator default_allocator = { +static UcxAllocator default_allocator = { NULL, ucx_default_malloc, ucx_default_calloc, diff -r bf3695fee719 -r 481802342fdf ucx/avl.c --- a/ucx/avl.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/avl.c Mon Feb 04 17:17:48 2019 +0100 @@ -136,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; diff -r bf3695fee719 -r 481802342fdf ucx/buffer.c --- a/ucx/buffer.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/buffer.c Mon Feb 04 17:17:48 2019 +0100 @@ -151,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; @@ -185,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; @@ -225,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 bf3695fee719 -r 481802342fdf ucx/list.c --- a/ucx/list.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/list.c Mon Feb 04 17:17:48 2019 +0100 @@ -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; @@ -106,41 +107,6 @@ } } -UcxList *ucx_list_append_once(UcxList *l, void *data, - cmp_func cmpfnc, void *cmpdata) { - return ucx_list_append_once_a(ucx_default_allocator(), l, - data, cmpfnc, cmpdata); -} - -UcxList *ucx_list_append_once_a(UcxAllocator *alloc, UcxList *l, void *data, - cmp_func cmpfnc, void *cmpdata) { - - UcxList *last = NULL; - { - UcxList *e = l; - while (e) { - if (cmpfnc(e->data, data, cmpdata) == 0) { - return l; - } - last = e; - e = e->next; - } - } - - UcxList *nl = ucx_list_append_a(alloc, NULL, data); - if (!nl) { - return NULL; - } - - if (last == NULL) { - return nl; - } else { - nl->prev = last; - last->next = nl; - return l; - } -} - UcxList *ucx_list_prepend(UcxList *l, void *data) { return ucx_list_prepend_a(ucx_default_allocator(), l, data); } diff -r bf3695fee719 -r 481802342fdf ucx/logging.c --- a/ucx/logging.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/logging.c Mon Feb 04 17:17:48 2019 +0100 @@ -50,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]"); } @@ -69,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); @@ -92,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 bf3695fee719 -r 481802342fdf ucx/map.c --- a/ucx/map.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/map.c Mon Feb 04 17:17:48 2019 +0100 @@ -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); + } } } @@ -150,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; + 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) { @@ -184,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; @@ -195,7 +203,7 @@ 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; @@ -235,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; } @@ -308,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 bf3695fee719 -r 481802342fdf ucx/mempool.c --- a/ucx/mempool.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/mempool.c Mon Feb 04 17:17:48 2019 +0100 @@ -65,12 +65,17 @@ } 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; @@ -100,7 +105,12 @@ return 1; } - void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); + 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; @@ -111,6 +121,10 @@ } void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { + if(((size_t)-1) - sizeof(ucx_destructor) < n) { + return NULL; + } + if (pool->ndata >= pool->size) { size_t newcap = pool->size*2; if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) { @@ -132,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; } @@ -141,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) { diff -r bf3695fee719 -r 481802342fdf ucx/stack.c --- a/ucx/stack.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/stack.c Mon Feb 04 17:17:48 2019 +0100 @@ -120,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); } @@ -142,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 bf3695fee719 -r 481802342fdf ucx/string.c --- a/ucx/string.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/string.c Mon Feb 04 17:17:48 2019 +0100 @@ -50,13 +50,33 @@ 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, ...) { 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); @@ -67,8 +87,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; @@ -77,7 +96,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; } @@ -85,16 +110,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) { @@ -137,44 +193,80 @@ } 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); +} + +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 ? \ @@ -185,13 +277,21 @@ else ((size_t*)ptable)[index] = src;\ } while (0); -sstr_t sstrstr(sstr_t string, sstr_t match) { - if (match.length == 0) { - return string; + +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; } - /* prepare default return value in case of no match */ - sstr_t result = sstrn(NULL, 0); + const char *result = NULL; + size_t resultlen = 0; /* * IMPORTANT: @@ -206,9 +306,9 @@ /* check pattern length and use appropriate prefix table */ /* if the pattern exceeds static prefix table, allocate on the heap */ - register int useheap = match.length > 255; + register int useheap = matchlen > 255; register void* ptable = useheap ? - calloc(match.length+1, sizeof(size_t)): s_prefix_table; + calloc(matchlen+1, sizeof(size_t)): s_prefix_table; /* keep counter in registers */ register size_t i, j; @@ -216,8 +316,8 @@ /* fill prefix table */ i = 0; j = 0; ptable_w(useheap, ptable, i, j); - while (i < match.length) { - while (j >= 1 && match.ptr[j-1] != match.ptr[i]) { + while (i < matchlen) { + while (j >= 1 && match[j-1] != match[i]) { ptable_r(j, useheap, ptable, j-1); } i++; j++; @@ -226,15 +326,15 @@ /* search */ i = 0; j = 1; - while (i < string.length) { - while (j >= 1 && string.ptr[i] != match.ptr[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 == match.length) { - size_t start = i - match.length; - result.ptr = string.ptr + start; - result.length = string.length - start; + if (j-1 == matchlen) { + size_t start = i - matchlen; + result = str + start; + resultlen = length - start; break; } } @@ -244,17 +344,54 @@ free(ptable); } + *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; +} + +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; } #undef ptable_r #undef ptable_w -sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { - return sstrsplit_a(ucx_default_allocator(), s, d, n); +sstr_t* scstrsplit(scstr_t s, scstr_t d, ssize_t *n) { + return scstrsplit_a(ucx_default_allocator(), s, d, n); } -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *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; @@ -269,20 +406,24 @@ } else /* no match possible */ { *n = 1; sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)); - *result = sstrdup_a(allocator, s); + if(result) { + *result = sstrdup_a(allocator, s); + } else { + *n = -2; + } return result; } } ssize_t nmax = *n; size_t arrlen = 16; - sstr_t* result = (sstr_t*) almalloc(allocator, arrlen*sizeof(sstr_t)); + sstr_t* result = (sstr_t*) alcalloc(allocator, arrlen, sizeof(sstr_t)); if (result) { - sstr_t curpos = s; + scstr_t curpos = s; ssize_t j = 1; while (1) { - sstr_t match; + scstr_t match; /* optimize for one byte delimiters */ if (d.length == 1) { match = curpos; @@ -294,13 +435,13 @@ match.length--; } } else { - match = sstrstr(curpos, d); + 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 */ - sstr_t item = sstrn(curpos.ptr, match.ptr - curpos.ptr); + 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; @@ -310,8 +451,12 @@ j++; if (j > arrlen) { arrlen *= 2; - sstr_t* reallocated = (sstr_t*) alrealloc( - allocator, result, arrlen*sizeof(sstr_t)); + 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 { @@ -342,7 +487,7 @@ 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) { @@ -352,7 +497,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); @@ -366,11 +511,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) { @@ -385,21 +530,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; } @@ -414,7 +576,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; } @@ -430,7 +592,7 @@ } } -sstr_t sstrlower(sstr_t string) { +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]); @@ -438,7 +600,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]); @@ -446,7 +608,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]); @@ -454,10 +616,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 bf3695fee719 -r 481802342fdf ucx/ucx.c --- a/ucx/ucx.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx.c Mon Feb 04 17:17:48 2019 +0100 @@ -44,3 +44,19 @@ */ #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 bf3695fee719 -r 481802342fdf ucx/ucx/avl.h --- a/ucx/ucx/avl.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/avl.h Mon Feb 04 17:17:48 2019 +0100 @@ -125,7 +125,7 @@ * * 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. + * ucx_cmp_str() function here. * * @param cmpfunc the compare function that shall be used * @param allocator the UcxAllocator that shall be used @@ -135,17 +135,43 @@ /** * 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_ptrcmp() compare function. + * ucx_cmp_ptr() compare function. * * @return a new default UcxAVLTree object */ -#define ucx_avl_default_new() ucx_avl_new_a(ucx_ptrcmp, ucx_default_allocator()) +#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. diff -r bf3695fee719 -r 481802342fdf ucx/ucx/buffer.h --- a/ucx/ucx/buffer.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/buffer.h Mon Feb 04 17:17:48 2019 +0100 @@ -137,6 +137,67 @@ #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. * @@ -165,8 +226,8 @@ * * @param buffer the buffer to be cleared */ -#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ - buffer->size = 0; buffer->pos = 0; +#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. @@ -260,7 +321,15 @@ * @param str the string * @return the number of bytes written */ -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); +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 } diff -r bf3695fee719 -r 481802342fdf ucx/ucx/list.h --- a/ucx/ucx/list.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/list.h Mon Feb 04 17:17:48 2019 +0100 @@ -173,9 +173,11 @@ * * 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 the destructor function (e.g. stdlib free()) + * @param destr optional destructor function * @see ucx_list_free() */ void ucx_list_free_content(UcxList* list, ucx_destructor destr); @@ -210,40 +212,6 @@ */ UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); -/** - * Inserts an element at the end of the list, if it is not present in the list. - * - * - * @param list the list where to append the data, or NULL to - * create a new list - * @param data the data to insert - * @param cmpfnc the compare function - * @param cmpdata additional data for the compare function - * @return list, if it is not NULL or a pointer to - * the newly created list otherwise - * @see ucx_list_append() - */ -UcxList *ucx_list_append_once(UcxList *list, void *data, - cmp_func cmpfnc, void *cmpdata); - -/** - * Inserts an element at the end of the list, if it is not present in 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 - * @param cmpfnc the compare function - * @param cmpdata additional data for the compare function - * @return list, if it is not NULL or a pointer to - * the newly created list otherwise - * @see ucx_list_append_a() - */ -UcxList *ucx_list_append_once_a(UcxAllocator *allocator, - UcxList *list, void *data, cmp_func cmpfnc, void *cmpdata); /** * Inserts an element at the beginning of the list. diff -r bf3695fee719 -r 481802342fdf ucx/ucx/logging.h --- a/ucx/ucx/logging.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/logging.h Mon Feb 04 17:17:48 2019 +0100 @@ -177,6 +177,18 @@ 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 diff -r bf3695fee719 -r 481802342fdf ucx/ucx/map.h --- a/ucx/ucx/map.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/map.h Mon Feb 04 17:17:48 2019 +0100 @@ -89,26 +89,36 @@ size_t count; }; -/** Structure for a key of a UcxMap. */ +/** Structure to publicly denote a key of a UcxMap. */ struct UcxKey { /** The key data. */ - void *data; + const void *data; /** The length of the key data. */ - size_t len; + 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; + int hash; }; /** Structure for an element of a UcxMap. */ struct UcxMapElement { /** The value data. */ - void *data; + void *data; /** A pointer to the next element in the current list. */ - UcxMapElement *next; + UcxMapElement *next; /** The corresponding key. */ - UcxKey key; + struct UcxMapKey key; }; /** Structure for an iterator over a UcxMap. */ @@ -158,7 +168,10 @@ * 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()). + * 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. @@ -166,7 +179,7 @@ * 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 + * @param destr optional pointer to a destructor function * @see ucx_map_free() * @see ucx_map_clear() */ @@ -282,7 +295,7 @@ * @see ucx_map_put() */ #define ucx_map_cstr_put(map, key, value) \ - ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value) + ucx_map_put(map, ucx_key(key, strlen(key)), (void*)value) /** * Shorthand for putting data with an integer key into the map. @@ -293,7 +306,7 @@ * @see ucx_map_put() */ #define ucx_map_int_put(map, key, value) \ - ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value) + ucx_map_put(map, ucx_key(&key, sizeof(key)), (void*)value) /** * Shorthand for getting data from the map with a sstr_t key. @@ -313,7 +326,7 @@ * @see ucx_map_get() */ #define ucx_map_cstr_get(map, key) \ - ucx_map_get(map, ucx_key((void*)key, strlen(key))) + ucx_map_get(map, ucx_key(key, strlen(key))) /** * Shorthand for getting data from the map with an integer key. @@ -323,7 +336,7 @@ * @see ucx_map_get() */ #define ucx_map_int_get(map, key) \ - ucx_map_get(map, ucx_key((void*)&key, sizeof(int))) + ucx_map_get(map, ucx_key(&key, sizeof(int))) /** * Shorthand for removing data from the map with a sstr_t key. @@ -343,7 +356,7 @@ * @see ucx_map_remove() */ #define ucx_map_cstr_remove(map, key) \ - ucx_map_remove(map, ucx_key((void*)key, strlen(key))) + ucx_map_remove(map, ucx_key(key, strlen(key))) /** * Shorthand for removing data from the map with an integer key. @@ -353,7 +366,7 @@ * @see ucx_map_remove() */ #define ucx_map_int_remove(map, key) \ - ucx_map_remove(map, ucx_key((void*)&key, sizeof(key))) + ucx_map_remove(map, ucx_key(&key, sizeof(key))) /** * Creates a UcxKey based on the given data. @@ -365,7 +378,7 @@ * @return a UcxKey with implicitly computed hash * @see ucx_hash() */ -UcxKey ucx_key(void *data, size_t len); +UcxKey ucx_key(const void *data, size_t len); /** * Computes a murmur hash-2. diff -r bf3695fee719 -r 481802342fdf ucx/ucx/mempool.h --- a/ucx/ucx/mempool.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/mempool.h Mon Feb 04 17:17:48 2019 +0100 @@ -164,6 +164,9 @@ * * 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 @@ -179,12 +182,18 @@ /** * 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 diff -r bf3695fee719 -r 481802342fdf ucx/ucx/properties.h --- a/ucx/ucx/properties.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/properties.h Mon Feb 04 17:17:48 2019 +0100 @@ -173,12 +173,15 @@ * 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. + * 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); diff -r bf3695fee719 -r 481802342fdf ucx/ucx/stack.h --- a/ucx/ucx/stack.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/stack.h Mon Feb 04 17:17:48 2019 +0100 @@ -91,19 +91,23 @@ * * @param stack a pointer to the stack * @param n amount of memory to allocate - * @return a pointer to the allocated memory + * @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); /** - * Alias for #ucx_stack_malloc(). + * 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 */ -#define ucx_stack_push(stack, n) ucx_stack_malloc(stack, n) +void *ucx_stack_push(UcxStack *stack, size_t n, const void *data); /** * Allocates an array of stack memory @@ -119,15 +123,18 @@ void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize); /** - * Alias for #ucx_stack_calloc(). + * Allocates memory with #ucx_stack_calloc() and copies the specified data if + * the allocation was successful. * * @param stack a pointer to the stack - * @param n amount of elements to allocate + * @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 */ -#define ucx_stack_pusharr(stack,n,elsize) ucx_stack_calloc(stack,n,elssize) +void *ucx_stack_pusharr(UcxStack *stack, + size_t nelem, size_t elsize, const void *data); /** * Reallocates memory on the stack. @@ -184,12 +191,13 @@ * 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. + * 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 elements to dest + * @param n copies at most n bytes to dest * @see ucx_stack_pop */ void ucx_stack_popn(UcxStack *stack, void *dest, size_t n); diff -r bf3695fee719 -r 481802342fdf ucx/ucx/string.h --- a/ucx/ucx/string.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/string.h Mon Feb 04 17:17:48 2019 +0100 @@ -52,26 +52,192 @@ #include "allocator.h" #include -/** Shortcut for a sstr_t struct literal. */ -#define ST(s) { (char*)s, sizeof(s)-1 } +/* + * 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((char*)s, sizeof(s)-1) +#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 a 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 a 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 the an immutable version of the provided string + */ +#define SCSTR(s) s2scstr(s) +#else + +/** + * One of two type adjustment functions that return a 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 a 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 the 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 the 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 -/** - * 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. @@ -81,6 +247,8 @@ * 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. * + * 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 * @@ -94,6 +262,8 @@ * 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. * + * 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 @@ -103,21 +273,57 @@ */ 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 hold a reference 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 hold a reference 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 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 + * @param ... all strings * @return the cumulated length of all strings */ -size_t sstrnlen(size_t count, sstr_t string, ...); +size_t scstrnlen(size_t count, ...); + +/** + * Alias for scstrnlen() which automatically converts the arguments. + * + * @param count the total number of specified strings (so at least 1) + * @param ... all strings + * @return the cumulated length of all strings + */ +#define sstrnlen(count, ...) scstrnlen(count, __VA_ARGS__) /** * Concatenates two or more strings. @@ -130,26 +336,47 @@ * * @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 scstrcat(size_t count, scstr_t s1, ...); + +/** + * Alias for scstrcat() which automatically converts the arguments. + * + * @param count the total number of strings to concatenate + * @param s1 first string * @param ... all remaining strings * @return the concatenated string */ -sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); +#define sstrcat(count, s1, ...) scstrcat(count, SCSTR(s1), __VA_ARGS__) /** * Concatenates two or more strings using a UcxAllocator. * + * See scstrcat() for details. + * + * @param a 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 + */ +sstr_t scstrcat_a(UcxAllocator *a, size_t count, scstr_t s1, ...); + +/** + * Alias for scstrcat_a() which automatically converts the arguments. + * * 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, ...); - +#define sstrcat_a(a, count, s1, ...) \ + scstrcat_a(a, count, SCSTR(s1), __VA_ARGS__) /** * Returns a substring starting at the specified location. @@ -186,6 +413,42 @@ 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 will NOT 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 will NOT 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. * @@ -214,6 +477,34 @@ 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. * @@ -228,7 +519,46 @@ * match, or an empty string, if the sequence is not * present in string */ -sstr_t sstrstr(sstr_t string, sstr_t match); +sstr_t scstrsstr(sstr_t string, scstr_t match); + +/** + * Alias for scstrsstr() which automatically converts the match string. + * + * @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); + +/** + * Alias for scstrscstr() which automatically converts the match string. + * + * @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. @@ -273,16 +603,31 @@ * @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 + * NULL on error + * + * @see scstrsplit_a() + */ +sstr_t* scstrsplit(scstr_t string, scstr_t delim, ssize_t *count); + +/** + * Alias for scstrsplit() which automatically converts the arguments. + * + * @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); +#define sstrsplit(string, delim, count) \ + scstrsplit(SCSTR(string), SCSTR(delim), count) /** - * Performing sstrsplit() using a UcxAllocator. + * Performing scstrsplit() using a UcxAllocator. * - * Read the description of sstrsplit() for details. + * 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() @@ -297,17 +642,33 @@ * @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 + * NULL on error + * + * @see scstrsplit() + */ +sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t string, scstr_t delim, + ssize_t *count); + +/** + * Alias for scstrsplit_a() which automatically converts the arguments. + * + * @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); +#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 sstr_t.length attribute of the two strings. The + * 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 @@ -316,23 +677,44 @@ * 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); +int scstrcmp(scstr_t s1, scstr_t s2); + +/** + * Alias for scstrcmp() which automatically converts its arguments. + * + * @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 sstr_t.length attribute of the two strings. If and + * 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 difference between the - * first two differing characters otherwise (i.e. 0 if the strings match and - * no characters differ) + * length of s1 is greater than the length of s2 or the result of the platform + * specific string comparison function ignoring the case. */ -int sstrcasecmp(sstr_t s1, sstr_t s2); +int scstrcasecmp(scstr_t s1, scstr_t s2); + +/** + * Alias for scstrcasecmp() which automatically converts the arguments. + * + * @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. @@ -342,31 +724,51 @@ * free(). * * The sstr_t.ptr of the return value will always be NULL- - * terminated. + * 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); + +/** + * Alias for scstrdup() which automatically converts the argument. * * @param string the string to duplicate * @return a duplicate of the string * @see sstrdup_a() */ -sstr_t sstrdup(sstr_t string); +#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 - * ucx_allocator_malloc function. So it is implementation depended, whether the + * UcxAllocator.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. + * UcxAllocator.free() function manually. * * The sstr_t.ptr of the return value will always be NULL- - * terminated. + * 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 sstrdup() + * @see scstrdup() */ -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string); +sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t string); + +/** + * Alias for scstrdup_a() which automatically converts 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. @@ -388,12 +790,40 @@ 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 sstrprefix(sstr_t string, sstr_t prefix); +int scstrprefix(scstr_t string, scstr_t prefix); + +/** + * Alias for scstrprefix() which automatically converts the arguments. + * + * @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. @@ -401,57 +831,101 @@ * @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); +int scstrsuffix(scstr_t string, scstr_t suffix); + +/** + * Alias for scstrsuffix() which automatically converts the arguments. + * + * @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)) /** * 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. + * documentation of scstrdup() for the implications. * * @param string the input string * @return the resulting lower case string - * @see sstrdup() + * @see scstrdup() */ -sstr_t sstrlower(sstr_t string); +sstr_t scstrlower(scstr_t string); + +/** + * Alias for scstrlower() which automatically converts the argument. + * + * @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 the - * documentation of sstrdup_a() for the implications. + * documentation of scstrdup_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() + * @see scstrdup_a() */ -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string); +sstr_t scstrlower_a(UcxAllocator *allocator, scstr_t string); + + +/** + * Alias for scstrlower_a() which automatically converts the argument. + * + * @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 the - * documentation of sstrdup() for the implications. + * documentation of scstrdup() for the implications. * * @param string the input string * @return the resulting upper case string - * @see sstrdup() + * @see scstrdup() */ -sstr_t sstrupper(sstr_t string); +sstr_t scstrupper(scstr_t string); + +/** + * Alias for scstrupper() which automatically converts the argument. + * + * @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 the - * documentation of sstrdup_a() for the implications. + * documentation of scstrdup_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() + * @see scstrdup_a() */ -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string); +sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string); + +/** + * Alias for scstrupper_a() which automatically converts the argument. + * + * @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 } diff -r bf3695fee719 -r 481802342fdf ucx/ucx/test.h --- a/ucx/ucx/test.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/test.h Mon Feb 04 17:17:48 2019 +0100 @@ -36,8 +36,8 @@ * **** IN HEADER FILE: **** * *
- * UCX_TEST(function_name)
- * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional
+ * UCX_TEST(function_name);
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist); // optional
  * 
* * **** IN SOURCE FILE: **** diff -r bf3695fee719 -r 481802342fdf ucx/ucx/ucx.h --- a/ucx/ucx/ucx.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/ucx.h Mon Feb 04 17:17:48 2019 +0100 @@ -37,7 +37,7 @@ #define UCX_H /** Major UCX version as integer constant. */ -#define UCX_VERSION_MAJOR 1 +#define UCX_VERSION_MAJOR 2 /** Minor UCX version as integer constant. */ #define UCX_VERSION_MINOR 0 @@ -131,6 +131,62 @@ */ 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 diff -r bf3695fee719 -r 481802342fdf ucx/ucx/utils.h --- a/ucx/ucx/utils.h Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/ucx/utils.h Mon Feb 04 17:17:48 2019 +0100 @@ -38,10 +38,6 @@ #ifndef UCX_UTILS_H #define UCX_UTILS_H -#ifdef __cplusplus -extern "C" { -#endif - #include "ucx.h" #include "string.h" #include "allocator.h" @@ -49,6 +45,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy(). */ @@ -144,7 +144,7 @@ * @param data omitted * @return the result of strcmp(s1, s2) */ -int ucx_strcmp(const void *s1, const void *s2, void *data); +int ucx_cmp_str(const void *s1, const void *s2, void *data); /** * Wraps the strncmp function. @@ -153,7 +153,16 @@ * @param n a pointer to the size_t containing the third strncmp parameter * @return the result of strncmp(s1, s2, *n) */ -int ucx_strncmp(const void *s1, const void *s2, void *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. @@ -163,7 +172,36 @@ * @return -1, if *i1 is less than *i2, 0 if both are equal, * 1 if *i1 is greater than *i2 */ -int ucx_intcmp(const void *i1, const void *i2, void *data); +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); + + +/** + * 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); /** * Compares two real numbers of type float. @@ -174,7 +212,7 @@ * 1 if *f1 is greater than *f2 */ -int ucx_floatcmp(const void *f1, const void *f2, void *data); +int ucx_cmp_float(const void *f1, const void *f2, void *data); /** * Compares two real numbers of type double. @@ -184,7 +222,7 @@ * @return -1, if *d1 is less than *d2, 0 if both are equal, * 1 if *d1 is greater than *d2 */ -int ucx_doublecmp(const void *d1, const void *d2, void *data); +int ucx_cmp_double(const void *d1, const void *d2, void *data); /** * Compares two pointers. @@ -194,7 +232,7 @@ * @return -1 if ptr1 is less than ptr2, 0 if both are equal, * 1 if ptr1 is greater than ptr2 */ -int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data); +int ucx_cmp_ptr(const void *ptr1, const void *ptr2, void *data); /** * Compares two memory areas. @@ -203,7 +241,7 @@ * @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(const void *ptr1, const void *ptr2, void *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 diff -r bf3695fee719 -r 481802342fdf ucx/utils.c --- a/ucx/utils.c Mon Feb 04 14:11:57 2019 +0100 +++ b/ucx/utils.c Mon Feb 04 17:17:48 2019 +0100 @@ -88,15 +88,21 @@ /* COMPARE FUNCTIONS */ -int ucx_strcmp(const void *s1, const void *s2, void *data) { +int ucx_cmp_str(const void *s1, const void *s2, void *data) { return strcmp((const char*)s1, (const char*)s2); } -int ucx_strncmp(const void *s1, const void *s2, void *n) { +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_intcmp(const void *i1, const void *i2, void *data) { +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) { @@ -106,7 +112,29 @@ } } -int ucx_floatcmp(const void *f1, const void *f2, void *epsilon) { +int ucx_cmp_longint(const void *i1, const void *i2, void *data) { + int a = *((const long int*) i1); + int b = *((const long int*) 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; +} + +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); @@ -117,7 +145,7 @@ } } -int ucx_doublecmp(const void *d1, const void *d2, void *epsilon) { +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); @@ -128,7 +156,7 @@ } } -int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data) { +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) { @@ -138,7 +166,7 @@ } } -int ucx_memcmp(const void *ptr1, const void *ptr2, void *n) { +int ucx_cmp_mem(const void *ptr1, const void *ptr2, void *n) { return memcmp(ptr1, ptr2, *((size_t*)n)); }