Mon, 23 May 2016 12:28:32 +0200
added support for icons for the table widget (GTK)
--- a/application/main.c Tue Feb 16 17:39:33 2016 +0100 +++ b/application/main.c Mon May 23 12:28:32 2016 +0200 @@ -97,6 +97,15 @@ //*/ } +void* model_getval(void *obj, int col) { + if(col == 0) { + return "folder"; + } else if(col == 2) { + return "test@localhost"; + } + return obj; +} + UIMENU ctxmenu; void click(UiEvent *event, void *data) { UiMouseEvent *me = event->eventdata; @@ -141,22 +150,9 @@ ui_context_closefunc(obj->ctx, window_close, NULL); ///* - ui_vbox_sp(obj, 8, 4); - - ui_textfield(obj, NULL); - ui_passwordfield(obj, NULL); - ui_frameless_textfield(obj, NULL); - - ui_layout_fill(obj, FALSE); - ui_hbox_sp(obj, 0, 10); - ui_textfield_w(obj, 5, NULL); - ui_textfield_w(obj, 10, NULL); - ui_textfield(obj, NULL); - ui_end(obj); - - ui_textarea(obj, NULL); - - ui_end(obj); + UiModelInfo *modeldesc = ui_model_info(obj->ctx, UI_ICON_TEXT, "Name", UI_STRING, "Mail", -1); + modeldesc->getvalue = model_getval; + ui_table(obj, list, modeldesc); //*/ ui_show(obj);
--- a/ucx/allocator.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/allocator.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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:
--- a/ucx/allocator.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/allocator.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -157,6 +157,41 @@ 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 <code>struct</code> definition. */ #define UCX_ALLOCATOR_DEFAULT {NULL, \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/avl.c Mon May 23 12:28:32 2016 +0200 @@ -0,0 +1,272 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 "avl.h" + +#define ptrcast(ptr) ((void*)(ptr)) + +static void ucx_avl_connect(UcxAVLTree *tree, + UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) { + if (child) { + child->parent = node; + } + // if child is NULL, nullkey decides if left or right pointer is cleared + if (tree->cmpfunc( + ptrcast(child ? child->key : nullkey), + ptrcast(node->key), tree->userdata) > 0) { + node->right = child; + } else { + node->left = child; + } + size_t lh = node->left ? node->left->height : 0; + size_t rh = node->right ? node->right->height : 0; + node->height = 1 + (lh > rh ? lh : rh); +} + +#define avlheight(node) ((node) ? (node)->height : 0) + +static UcxAVLNode* avl_rotright(UcxAVLTree *tree, UcxAVLNode *l0) { + UcxAVLNode *p = l0->parent; + UcxAVLNode *l1 = l0->left; + if (p) { + ucx_avl_connect(tree, p, l1, 0); + } else { + l1->parent = NULL; + } + ucx_avl_connect(tree, l0, l1->right, l1->key); + ucx_avl_connect(tree, l1, l0, 0); + return l1; +} + +static UcxAVLNode* avl_rotleft(UcxAVLTree *tree, UcxAVLNode *l0) { + UcxAVLNode *p = l0->parent; + UcxAVLNode *l1 = l0->right; + if (p) { + ucx_avl_connect(tree, p, l1, 0); + } else { + l1->parent = NULL; + } + ucx_avl_connect(tree, l0, l1->left, l1->key); + ucx_avl_connect(tree, l1, l0, 0); + return l1; +} + +static void ucx_avl_balance(UcxAVLTree *tree, UcxAVLNode *n) { + int lh = avlheight(n->left); + int rh = avlheight(n->right); + n->height = 1 + (lh > rh ? lh : rh); + + if (lh - rh == 2) { + UcxAVLNode *c = n->left; + if (avlheight(c->right) - avlheight(c->left) == 1) { + avl_rotleft(tree, c); + } + n = avl_rotright(tree, n); + } else if (rh - lh == 2) { + UcxAVLNode *c = n->right; + if (avlheight(c->left) - avlheight(c->right) == 1) { + avl_rotright(tree, c); + } + n = avl_rotleft(tree, n); + } + + if (n->parent) { + ucx_avl_balance(tree, n->parent); + } else { + tree->root = n; + } +} + +UcxAVLTree *ucx_avl_new(cmp_func cmpfunc) { + return ucx_avl_new_a(cmpfunc, ucx_default_allocator()); +} + +UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) { + UcxAVLTree *tree = almalloc(allocator, sizeof(UcxAVLTree)); + if (tree) { + tree->allocator = allocator; + tree->cmpfunc = cmpfunc; + tree->root = NULL; + tree->userdata = NULL; + } + + return tree; +} + +static void ucx_avl_free_node(UcxAllocator *al, UcxAVLNode *node) { + if (node) { + ucx_avl_free_node(al, node->left); + ucx_avl_free_node(al, node->right); + alfree(al, node); + } +} + +void ucx_avl_free(UcxAVLTree *tree) { + UcxAllocator *al = tree->allocator; + ucx_avl_free_node(al, tree->root); + alfree(al, tree); +} + +UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) { + UcxAVLNode *n = tree->root; + int cmpresult; + while (n && (cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + n = cmpresult > 0 ? n->right : n->left; + } + return n; +} + +void *ucx_avl_get(UcxAVLTree *tree, intptr_t key) { + UcxAVLNode *n = ucx_avl_get_node(tree, key); + 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); +} + +int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, + void **oldvalue) { + if (tree->root) { + UcxAVLNode *n = tree->root; + int cmpresult; + while ((cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + UcxAVLNode *m = cmpresult > 0 ? n->right : n->left; + if (m) { + n = m; + } else { + break; + } + } + + if (cmpresult) { + UcxAVLNode *e = almalloc(tree->allocator, sizeof(UcxAVLNode)); + if (e) { + e->key = key; e->value = value; e->height = 1; + e->parent = e->left = e->right = NULL; + ucx_avl_connect(tree, n, e, 0); + ucx_avl_balance(tree, n); + return 0; + } else { + return 1; + } + } else { + if (oldvalue) { + *oldvalue = n->value; + } + n->value = value; + return 0; + } + } else { + tree->root = almalloc(tree->allocator, sizeof(UcxAVLNode)); + if (tree->root) { + tree->root->key = key; tree->root->value = value; + tree->root->height = 1; + tree->root->parent = tree->root->left = tree->root->right = NULL; + + if (oldvalue) { + *oldvalue = NULL; + } + + return 0; + } else { + return 1; + } + } +} + +int ucx_avl_remove(UcxAVLTree *tree, intptr_t key) { + return ucx_avl_remove_s(tree, key, NULL, NULL); +} + +int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node) { + return ucx_avl_remove_s(tree, node->key, NULL, NULL); +} + +int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, + intptr_t *oldkey, void **oldvalue) { + + UcxAVLNode *n = tree->root; + int cmpresult; + while (n && (cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + n = cmpresult > 0 ? n->right : n->left; + } + if (n) { + if (oldkey) { + *oldkey = n->key; + } + if (oldvalue) { + *oldvalue = n->value; + } + + UcxAVLNode *p = n->parent; + if (n->left && n->right) { + UcxAVLNode *s = n->right; + while (s->left) { + s = s->left; + } + ucx_avl_connect(tree, s->parent, s->right, s->key); + n->key = s->key; n->value = s->value; + p = s->parent; + alfree(tree->allocator, s); + } else { + if (p) { + ucx_avl_connect(tree, p, n->right ? n->right:n->left, n->key); + } else { + tree->root = n->right ? n->right : n->left; + if (tree->root) { + tree->root->parent = NULL; + } + } + alfree(tree->allocator, n); + } + + if (p) { + ucx_avl_balance(tree, p); + } + + return 0; + } else { + return 1; + } +} + +static size_t ucx_avl_countn(UcxAVLNode *node) { + if (node) { + return 1 + ucx_avl_countn(node->left) + ucx_avl_countn(node->right); + } else { + return 0; + } +} + +size_t ucx_avl_count(UcxAVLTree *tree) { + return ucx_avl_countn(tree->root); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/avl.h Mon May 23 12:28:32 2016 +0200 @@ -0,0 +1,249 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 <stdint.h> + +#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 an 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 <code>NULL</code>, 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 <code>NULL</code>, 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 */ +
--- a/ucx/buffer.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/buffer.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -31,22 +31,22 @@ #include <stdlib.h> #include <string.h> -UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags) { +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) { UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); if (buffer) { buffer->flags = flags; if (!space) { - buffer->space = (char*)malloc(size); + buffer->space = (char*)malloc(capacity); if (!buffer->space) { free(buffer); return NULL; } - memset(buffer->space, 0, size); + memset(buffer->space, 0, capacity); buffer->flags |= UCX_BUFFER_AUTOFREE; } else { buffer->space = (char*)space; } - buffer->capacity = size; + buffer->capacity = capacity; buffer->size = 0; buffer->pos = 0; @@ -64,13 +64,8 @@ UcxBuffer* ucx_buffer_extract( UcxBuffer *src, size_t start, size_t length, int flags) { - if(src->size == 0) { - return NULL; - } - if (length == 0) { - length = src->size - start; - } - if (start+length > src->size) { + + if (src->size == 0 || length == 0 || start+length > src->capacity) { return NULL; } @@ -99,13 +94,21 @@ case SEEK_END: npos = buffer->size; break; + case SEEK_SET: + npos = 0; + break; default: - npos = 0; + return -1; } + size_t opos = npos; npos += offset; - if (npos > buffer->size) { + if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { + return -1; + } + + if (npos >= buffer->size) { return -1; } else { buffer->pos = npos; @@ -120,7 +123,17 @@ int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { size_t newcap = buffer->capacity; - while (buffer->pos + len > newcap) newcap <<= 1; + + if (buffer->capacity + len < buffer->capacity) { + return -1; + } + + while (buffer->capacity + len > newcap) { + newcap <<= 1; + if (newcap < buffer->capacity) { + return -1; + } + } char *newspace = (char*)realloc(buffer->space, newcap); if (newspace) { @@ -137,18 +150,25 @@ size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, UcxBuffer *buffer) { size_t len = size * nitems; - if (buffer->pos + len > buffer->capacity) { + size_t required = buffer->pos + len; + if (buffer->pos > required) { + return 0; + } + + if (required > buffer->capacity) { if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - if(ucx_buffer_extend(buffer, len)) { - return -1; + if (ucx_buffer_extend(buffer, required - buffer->capacity)) { + return 0; } } else { len = buffer->capacity - buffer->pos; - if (size > 1) len -= len%size; + if (size > 1) { + len -= len%size; + } } } - if (len <= 0) { + if (len == 0) { return len; }
--- a/ucx/buffer.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/buffer.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -97,11 +97,11 @@ * * @param space pointer to the memory area, or <code>NULL</code> to allocate * new memory - * @param size the size of the buffer + * @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 size, int flags); +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); /** * Destroys a buffer. @@ -120,10 +120,9 @@ * * @param src the source buffer * @param start the start position of extraction - * @param length the count of bytes to extract or 0 if all of the remaining - * bytes shall be extracted + * @param length the count of bytes to extract (must not be zero) * @param flags feature mask for the new buffer - * @return + * @return a new buffer containing the extraction */ UcxBuffer* ucx_buffer_extract(UcxBuffer *src, size_t start, size_t length, int flags); @@ -136,7 +135,7 @@ * @return a new buffer with the extracted content */ #define ucx_buffer_clone(src,flags) \ - ucx_buffer_extract(src, 0, 0, flags) + ucx_buffer_extract(src, 0, (src)->capacity, flags) /** * Moves the position of the buffer. @@ -145,7 +144,11 @@ * * SEEK_SET marks the start of the buffer. * SEEK_CUR marks the current position. - * SEEK_END marks the first 0-byte in the buffer. + * 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 <code>whence</code> @@ -182,12 +185,12 @@ * the buffer capacity is doubled, as long as it would not hold the current * content plus the additional required bytes. * - * <b>Attention:</b> the argument provided is the count of <i>additional</i> - * bytes the buffer shall hold. It is <b>NOT</b> the total count of bytes the + * <b>Attention:</b> the argument provided is the number of <i>additional</i> + * bytes the buffer shall hold. It is <b>NOT</b> the total number of bytes the * buffer shall hold. * * @param buffer the buffer to extend - * @param additional_bytes the count of additional bytes the buffer shall + * @param additional_bytes the number of additional bytes the buffer shall * <i>at least</i> hold * @return 0 on success or a non-zero value on failure */ @@ -216,7 +219,7 @@ * @param size the length of one element * @param nitems the element count * @param buffer the UcxBuffer to read from - * @return the total count of bytes read + * @return the total number of elements read */ size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, UcxBuffer *buffer);
--- a/ucx/list.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/list.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -72,7 +72,7 @@ while (e != NULL) { f = e; e = e->next; - alloc->free(alloc->pool, f); + alfree(alloc, f); } } @@ -81,7 +81,7 @@ } UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { - UcxList *nl = (UcxList*) alloc->malloc(alloc->pool, sizeof(UcxList)); + UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList)); if (!nl) { return NULL; } @@ -121,7 +121,9 @@ if (l1) { UcxList *last = ucx_list_last(l1); last->next = l2; - l2->prev = last; + if (l2) { + l2->prev = last; + } return l1; } else { return l2; @@ -150,7 +152,7 @@ return -1; } -UcxList *ucx_list_get(const UcxList *l, int index) { +UcxList *ucx_list_get(const UcxList *l, size_t index) { if (l == NULL) return NULL; const UcxList *e = l; @@ -196,7 +198,7 @@ return s; } -UcxList *ucx_list_sort_merge(int length, +static UcxList *ucx_list_sort_merge(int length, UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, cmp_func fnc, void* data) { @@ -248,6 +250,8 @@ int ln = 1; UcxList *restrict ls = l, *restrict le, *restrict re; + + // check how many elements are already sorted lc = ls; while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { lc = lc->next; @@ -261,27 +265,30 @@ UcxList *rc; int rn = 1; rc = le; + // skip already sorted elements while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { rc = rc->next; rn++; } re = rc->next; - // Something left? Sort it! - UcxList *remainder = re; - size_t remainder_length = ucx_list_size(remainder); - if (remainder != NULL) { - remainder = ucx_list_sort(remainder, fnc, data); - } - // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them UcxList *sorted = ucx_list_sort_merge(ln+rn, ls, le, re, fnc, data); + + // Something left? Sort it! + size_t remainder_length = ucx_list_size(re); + if (remainder_length > 0) { + UcxList *remainder = ucx_list_sort(re, fnc, data); - // merge sorted list with (also sorted) remainder - l = ucx_list_sort_merge(ln+rn+remainder_length, - sorted, remainder, NULL, fnc, data); + // merge sorted list with (also sorted) remainder + l = ucx_list_sort_merge(ln+rn+remainder_length, + sorted, remainder, NULL, fnc, data); + } else { + // no remainder - we've got our sorted list + l = sorted; + } return l; } @@ -316,6 +323,6 @@ e->prev->next = e->next; } - alloc->free(alloc->pool, e); + alfree(alloc, e); return l; }
--- a/ucx/list.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/list.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -169,7 +169,7 @@ /** * Inserts an element at the end of the list. * - * This is generally an O(n) operation, as the end of the list is seeked with + * 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 <code>NULL</code> to @@ -273,7 +273,7 @@ * @return the element at the specified index or <code>NULL</code>, if the * index is greater than the list size */ -UcxList *ucx_list_get(const UcxList *list, int index); +UcxList *ucx_list_get(const UcxList *list, size_t index); /** * Returns the index of an element. @@ -350,7 +350,7 @@ * <code>mylist = ucx_list_remove(mylist, myelem);</code>. * * @param list the list from which the element shall be removed - * @param element the element to removed + * @param element the element to remove * @return returns the updated list pointer or <code>NULL</code>, if the list * is now empty */ @@ -363,7 +363,7 @@ * * @param allocator the allocator to use * @param list the list from which the element shall be removed - * @param element the element to removed + * @param element the element to remove * @return returns the updated list pointer or <code>NULL</code>, if the list * @see ucx_list_remove() */
--- a/ucx/logging.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/logging.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -75,6 +75,7 @@ if ((logger->mask & UCX_LOGGER_LEVEL) > 0) { text = (char*) ucx_map_int_get(logger->levels, level); n = strlen(text); + n = n > 256 ? 256 : n; memcpy(msg+k, text, n); k += n; msg[k++] = ' '; @@ -87,11 +88,7 @@ n = strlen(file); memcpy(msg+k, file, n); k += n; -#ifdef _WIN32 - k += _snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line); -#else - k += snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line); -#endif /* _WIN32 */ + k += sprintf(msg+k, ":%u ", line); } msg[k++] = '-'; msg[k++] = ' ';
--- a/ucx/logging.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/logging.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -97,7 +97,7 @@ write_func writer; /** - * The date format for timestamp outputs + * The date format for timestamp outputs including the delimiter * (default: <code>"%F %T %z "</code>). * @see UCX_LOGGER_TIMESTAMP */ @@ -162,7 +162,8 @@ * <code>[LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message</code> * * <b>Attention:</b> the message (including automatically generated information) - * <b>MUST NOT</b> exceed the size of 4 KB. + * 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
--- a/ucx/map.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/map.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -44,18 +44,16 @@ allocator = ucx_default_allocator(); } - UcxMap *map = (UcxMap*)allocator->malloc(allocator->pool, sizeof(UcxMap)); + UcxMap *map = (UcxMap*)almalloc(allocator, sizeof(UcxMap)); if (!map) { return NULL; } map->allocator = allocator; - map->map = (UcxMapElement**)allocator->calloc( - allocator->pool, - size, - sizeof(UcxMapElement*)); + map->map = (UcxMapElement**)alcalloc( + allocator, size, sizeof(UcxMapElement*)); if(map->map == NULL) { - allocator->free(allocator->pool, map); + alfree(allocator, map); return NULL; } map->size = size; @@ -64,24 +62,41 @@ return map; } -static void ucx_map_free_elmlist(UcxMap *map) { +static void ucx_map_free_elmlist_contents(UcxMap *map) { for (size_t n = 0 ; n < map->size ; n++) { UcxMapElement *elem = map->map[n]; if (elem != NULL) { do { UcxMapElement *next = elem->next; - map->allocator->free(map->allocator->pool, elem->key.data); - map->allocator->free(map->allocator->pool, elem); + alfree(map->allocator, elem->key.data); + alfree(map->allocator, elem); elem = next; } while (elem != NULL); } } - map->allocator->free(map->allocator->pool, map->map); } void ucx_map_free(UcxMap *map) { - ucx_map_free_elmlist(map); - map->allocator->free(map->allocator->pool, map); + ucx_map_free_elmlist_contents(map); + alfree(map->allocator, map->map); + alfree(map->allocator, map); +} + +void ucx_map_free_content(UcxMap *map, ucx_destructor destr) { + UcxMapIterator iter = ucx_map_iterator(map); + void *val; + UCX_MAP_FOREACH(key, val, iter) { + destr(val); + } +} + +void ucx_map_clear(UcxMap *map) { + if (map->count == 0) { + return; // nothing to do + } + ucx_map_free_elmlist_contents(map); + memset(map->map, 0, map->size*sizeof(UcxMapElement*)); + map->count = 0; } int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, @@ -116,10 +131,8 @@ oldmap.allocator = map->allocator; map->size = (map->count * 5) >> 1; - map->map = (UcxMapElement**)map->allocator->calloc( - map->allocator->pool, - map->size, - sizeof(UcxMapElement*)); + map->map = (UcxMapElement**)alcalloc( + map->allocator, map->size, sizeof(UcxMapElement*)); if (!map->map) { *map = oldmap; return 1; @@ -128,7 +141,8 @@ ucx_map_copy(&oldmap, map, NULL, NULL); /* free the UcxMapElement list of oldmap */ - ucx_map_free_elmlist(&oldmap); + ucx_map_free_elmlist_contents(&oldmap); + alfree(map->allocator, oldmap.map); } return 0; } @@ -150,9 +164,8 @@ } if (!elm || elm->key.hash != key.hash) { - UcxMapElement *e = (UcxMapElement*)allocator->malloc( - allocator->pool, - sizeof(UcxMapElement)); + UcxMapElement *e = (UcxMapElement*)almalloc( + allocator, sizeof(UcxMapElement)); if (!e) { return -1; } @@ -167,7 +180,7 @@ } if (!elm->key.data) { - void *kd = allocator->malloc(allocator->pool, key.len); + void *kd = almalloc(allocator, key.len); if (!kd) { return -1; } @@ -200,8 +213,8 @@ } else { map->map[slot] = elm->next; } - map->allocator->free(map->allocator->pool, elm->key.data); - map->allocator->free(map->allocator->pool, elm); + alfree(map->allocator, elm->key.data); + alfree(map->allocator, elm); map->count--; }
--- a/ucx/map.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/map.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -146,14 +146,45 @@ /** * Frees a hash map. * - * <b>Note:</b> the contents are <b>not</b> freed, use an UcxMempool for that - * purpose. + * <b>Note:</b> the contents are <b>not</b> 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. + * + * <b>Note:</b> the contents are <b>not</b> 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. * * <b>Note:</b> The destination map does not need to be empty. However, if it
--- a/ucx/mempool.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/mempool.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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:
--- a/ucx/mempool.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/mempool.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -47,13 +47,6 @@ #endif /** - * A function pointer to a destructor function. - * @see ucx_mempool_setdestr() - * @see ucx_mempool_regdestr() - */ -typedef void(*ucx_destructor)(void*); - -/** * UCX mempool structure. */ typedef struct { @@ -121,7 +114,7 @@ /** * Allocates a pooled memory array. * - * The contents of the allocated memory is set to zero. + * The content of the allocated memory is set to zero. * * @param pool the memory pool * @param nelem amount of elements to allocate @@ -142,7 +135,7 @@ * @param pool the memory pool * @param ptr a pointer to the memory that shall be reallocated * @param n the new size of the memory - * @return a pointer to the the location of the memory + * @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);
--- a/ucx/properties.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/properties.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -206,7 +206,7 @@ return 1; } if(ucx_map_sstr_put(map, name, value.ptr)) { - map->allocator->free(map->allocator->pool, value.ptr); + alfree(map->allocator, value.ptr); return 1; } }
--- a/ucx/properties.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/properties.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/stack.c Mon May 23 12:28:32 2016 +0200 @@ -0,0 +1,143 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 "stack.h" +#include <string.h> + +static size_t ucx_stack_align(size_t n) { + int align = n % sizeof(void*); + if (align) { + n += sizeof(void*) - align; + } + return n; +} + +void ucx_stack_init(UcxStack *stack, char* space, size_t size) { + stack->size = size - size % sizeof(void*); + stack->space = space; + stack->top = NULL; + + stack->allocator.pool = stack; + stack->allocator.malloc = (ucx_allocator_malloc) ucx_stack_malloc; + stack->allocator.calloc = (ucx_allocator_calloc) ucx_stack_calloc; + stack->allocator.realloc = (ucx_allocator_realloc) ucx_stack_realloc; + stack->allocator.free = (ucx_allocator_free) ucx_stack_free; +} + +void *ucx_stack_malloc(UcxStack *stack, size_t n) { + + if (ucx_stack_avail(stack) < ucx_stack_align(n)) { + return NULL; + } else { + char *prev = stack->top; + if (stack->top) { + stack->top += ucx_stack_align(ucx_stack_topsize(stack)); + } else { + stack->top = stack->space; + } + + ((struct ucx_stack_metadata*)stack->top)->prev = prev; + ((struct ucx_stack_metadata*)stack->top)->size = n; + stack->top += sizeof(struct ucx_stack_metadata); + + return stack->top; + } +} + +void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize) { + void *mem = ucx_stack_malloc(stack, nelem*elsize); + memset(mem, 0, nelem*elsize); + return mem; +} + +void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n) { + if (ptr == stack->top) { + if (stack->size - (stack->top - stack->space) < ucx_stack_align(n)) { + return NULL; + } else { + ((struct ucx_stack_metadata*)stack->top - 1)->size = n; + return ptr; + } + } else { + if (ucx_stack_align(((struct ucx_stack_metadata*)ptr - 1)->size) < + ucx_stack_align(n)) { + void *nptr = ucx_stack_malloc(stack, n); + if (nptr) { + memcpy(nptr, ptr, n); + ucx_stack_free(stack, ptr); + + return nptr; + } else { + return NULL; + } + } else { + ((struct ucx_stack_metadata*)ptr - 1)->size = n; + return ptr; + } + } +} + +void ucx_stack_free(UcxStack *stack, void *ptr) { + if (ptr == stack->top) { + stack->top = ((struct ucx_stack_metadata*) stack->top - 1)->prev; + } else { + struct ucx_stack_metadata *next = (struct ucx_stack_metadata*)( + (char*)ptr + + ucx_stack_align(((struct ucx_stack_metadata*) ptr - 1)->size) + ); + next->prev = ((struct ucx_stack_metadata*) ptr - 1)->prev; + } +} + +void ucx_stack_popn(UcxStack *stack, void *dest, size_t n) { + if (ucx_stack_empty(stack)) { + return; + } + + size_t len = ucx_stack_topsize(stack); + if (len > n) { + len = n; + } + + memcpy(dest, stack->top, len); + + ucx_stack_free(stack, stack->top); +} + +size_t ucx_stack_avail(UcxStack *stack) { + size_t avail = ((stack->top ? (stack->size + - (stack->top - stack->space) + - ucx_stack_align(ucx_stack_topsize(stack))) + : stack->size)); + + if (avail > sizeof(struct ucx_stack_metadata)) { + return avail - sizeof(struct ucx_stack_metadata); + } else { + return 0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/stack.h Mon May 23 12:28:32 2016 +0200 @@ -0,0 +1,233 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 <stdint.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 (<code>NULL</code> 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 <code> + * dest</code>, if specified. + * + * Use #ucx_stack_topsize()# to get the amount of memory that must be available + * at the location of <code>dest</code>. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to, or <code> + * NULL</code>, 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_MAX) + +/** + * Removes the top most element from the stack and copies the content to <code> + * dest</code>. + * + * In contrast to #ucx_stack_pop() the <code>dest</code> pointer <code>MUST + * NOT</code> be <code>NULL</code>. + * + * @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 <code>dest</code> + * @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 */ +
--- a/ucx/string.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/string.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -29,6 +29,7 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> +#include <ctype.h> #include "string.h" #include "allocator.h" @@ -61,32 +62,71 @@ return size; } -sstr_t sstrncat(sstr_t s, size_t n, sstr_t c1, ...) { - va_list ap; - va_start(ap, c1); - s.ptr[0] = 0; +static sstr_t sstrvcat_a( + UcxAllocator *a, + size_t count, + sstr_t s1, + sstr_t s2, + va_list ap) { + sstr_t str; + str.ptr = NULL; + str.length = 0; + if(count < 2) { + return str; + } - size_t len = s.length; - size_t cplen = c1.length > len ? len : c1.length; - char *ptr = s.ptr; + sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t)); + if(!strings) { + return str; + } + + // get all args and overall length + strings[0] = s1; + strings[1] = s2; + size_t strlen = s1.length + s2.length; + for (size_t i=2;i<count;i++) { + sstr_t s = va_arg (ap, sstr_t); + strings[i] = s; + strlen += s.length; + } - memcpy(ptr, c1.ptr, cplen); - len -= cplen; - ptr += cplen; - for (size_t i = 1 ; i < n ; i++) { - sstr_t str = va_arg (ap, sstr_t); - cplen = str.length > len ? len : str.length; - if(cplen <= 0) { - va_end(ap); - return s; - } - memcpy(ptr, str.ptr, cplen); - len -= cplen; - ptr += cplen; + // create new string + str.ptr = (char*) almalloc(a, strlen + 1); + str.length = strlen; + if(!str.ptr) { + free(strings); + str.length = 0; + return str; + } + + // concatenate strings + size_t pos = 0; + for (size_t i=0;i<count;i++) { + sstr_t s = strings[i]; + memcpy(str.ptr + pos, s.ptr, s.length); + pos += s.length; } + + str.ptr[str.length] = '\0'; + + free(strings); + + return str; +} + +sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...) { + va_list ap; + va_start(ap, s2); + sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, s2, ap); va_end(ap); - s.length = ptr - s.ptr; + return s; +} +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...) { + va_list ap; + va_start(ap, s2); + sstr_t s = sstrvcat_a(a, count, s1, s2, ap); + va_end(ap); return s; } @@ -97,13 +137,15 @@ sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) { sstr_t new_sstr; if (start >= s.length) { - return s; + new_sstr.ptr = NULL; + new_sstr.length = 0; + } else { + if (length > s.length-start) { + length = s.length-start; + } + new_sstr.ptr = &s.ptr[start]; + new_sstr.length = length; } - if (length > s.length-start) { - length = s.length-start; - } - new_sstr.ptr = &s.ptr[start]; - new_sstr.length = length; return new_sstr; } @@ -133,18 +175,18 @@ return n; } -sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) { +sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { return sstrsplit_a(ucx_default_allocator(), s, d, n); } -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, size_t *n) { +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) { if (s.length == 0 || d.length == 0) { *n = -1; return NULL; } sstr_t* result; - size_t nmax = *n; + ssize_t nmax = *n; *n = 1; /* special case: exact match - no processing needed */ @@ -179,18 +221,27 @@ } if ((*n) == nmax) break; } - result = (sstr_t*) allocator->malloc(allocator->pool, sizeof(sstr_t)*(*n)); + result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)*(*n)); if (result) { char *pptr = sv.ptr; - for (size_t i = 0 ; i < *n ; i++) { + for (ssize_t i = 0 ; i < *n ; i++) { size_t l = strlen(pptr); - char* ptr = (char*) allocator->malloc(allocator->pool, l + 1); - memcpy(ptr, pptr, l); - ptr[l] = 0; + char* ptr = (char*) almalloc(allocator, l + 1); + if (ptr) { + memcpy(ptr, pptr, l); + ptr[l] = 0; - result[i] = sstrn(ptr, l); - pptr += l + d.length; + result[i] = sstrn(ptr, l); + pptr += l + d.length; + } else { + for (ssize_t j = i-1 ; j >= 0 ; j--) { + alfree(allocator, result[j].ptr); + } + alfree(allocator, result); + *n = -2; + break; + } } } else { *n = -2; @@ -231,7 +282,7 @@ sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { sstr_t newstring; - newstring.ptr = (char*)allocator->malloc(allocator->pool, s.length + 1); + newstring.ptr = (char*)almalloc(allocator, s.length + 1); if (newstring.ptr) { newstring.length = s.length; newstring.ptr[newstring.length] = 0; @@ -246,38 +297,15 @@ sstr_t sstrtrim(sstr_t string) { sstr_t newstr = string; - if (string.length == 0) { - return newstr; - } - size_t i; - for(i=0;i<string.length;i++) { - char c = string.ptr[i]; - if(c > 32) { - break; - } + while (newstr.length > 0 && isspace(*newstr.ptr)) { + newstr.ptr++; + newstr.length--; } - newstr.ptr = &string.ptr[i]; - newstr.length = string.length - i; - - if(newstr.length == 0) { - return newstr; + while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) { + newstr.length--; } - i = newstr.length - 1; - for(;;) { - char c = newstr.ptr[i]; - if(c > 32) { - break; - } - if(i > 0) { - i--; - } else { - break; - } - } - newstr.length = i + 1; - return newstr; } @@ -311,3 +339,35 @@ suffix.ptr, suffix.length) == 0; } } + +sstr_t sstrlower(sstr_t string) { + sstr_t ret = sstrdup(string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = tolower(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_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]); + } + return ret; +} + +sstr_t sstrupper(sstr_t string) { + sstr_t ret = sstrdup(string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = toupper(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_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; +}
--- a/ucx/string.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/string.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -119,38 +119,36 @@ */ size_t sstrnlen(size_t count, sstr_t string, ...); +/** + * Concatenates two or more strings. + * + * The resulting string will be allocated by standard <code>malloc()</code>. + * So developers <b>MUST</b> pass the sstr_t.ptr to <code>free()</code>. + * + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- + * terminated. + * + * @param 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 strings. - * - * At least one string must be specified and there must be enough memory - * available referenced by the destination sstr_t.ptr for this function to - * successfully concatenate all specified strings. - * - * The sstr_t.length of the destination string specifies the capacity and - * should match the total memory available referenced by the destination - * sstr_t.ptr. This function <i>never</i> copies data beyond the capacity and - * does not modify any of the source strings. + * Concatenates two or more strings using an UcxAllocator. * - * <b>Attention:</b> - * <ul> - * <li>Any content in the destination string will be overwritten</li> - * <li>The destination sstr_t.ptr is <b>NOT</b> - * <code>NULL</code>-terminated</li> - * <li>The destination sstr_t.length is set to the total length of the - * concatenated strings</li> - * <li><i>Hint:</i> get a <code>NULL</code>-terminated string by performing - * <code>mystring.ptr[mystring.length]='\0'</code> after calling this - * function</li> - * </ul> + * See sstrcat() for details. * - * @param dest new sstr_t with capacity information and allocated memory + * @param a the allocator to use * @param count the total number of strings to concatenate - * @param src the first string - * @param ... all other strings - * @return the argument for <code>dest</code> is returned + * @param s1 first string + * @param s2 second string + * @param ... all remaining strings + * @return the concatenated string */ -sstr_t sstrncat(sstr_t dest, size_t count, sstr_t src, ...); +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...); /** @@ -227,7 +225,7 @@ * </ul> * * The integer referenced by <code>count</code> is used as input and determines - * the maximum size of the resulting list, i.e. the maximum count of splits to + * the maximum size of the resulting array, i.e. the maximum count of splits to * perform + 1. * * The integer referenced by <code>count</code> is also used as output and is @@ -237,36 +235,36 @@ * <li>-1, if either the string or the delimiter is an empty string</li> * <li>0, if the string equals the delimiter</li> * <li>1, if the string does not contain the delimiter</li> - * <li>the count of list items, otherwise</li> + * <li>the count of array items, otherwise</li> * </ul> * * If the string starts with the delimiter, the first item of the resulting - * list will be an empty string. + * array will be an empty string. * * If the string ends with the delimiter and the maximum list size is not - * exceeded, the last list item will be an empty string. + * exceeded, the last array item will be an empty string. * - * <b>Attention:</b> All list items <b>AND</b> all sstr_t.ptr of the list + * <b>Attention:</b> The array pointer <b>AND</b> all sstr_t.ptr of the array * items must be manually passed to <code>free()</code>. Use sstrsplit_a() with * an allocator to managed memory, to avoid this. * * @param string the string to split * @param delim the delimiter string - * @param count IN: the maximum size of the resulting list (0 for an - * unbounded list), OUT: the actual size of the list - * @return a list of the split strings as sstr_t array or + * @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 * <code>NULL</code> on error * * @see sstrsplit_a() */ -sstr_t* sstrsplit(sstr_t string, sstr_t delim, size_t *count); +sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); /** * Performing sstrsplit() using an UcxAllocator. * * <i>Read the description of sstrsplit() for details.</i> * - * The memory for the sstr_t.ptr pointers of the list items and the memory for + * The 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. * @@ -276,15 +274,15 @@ * @param allocator the UcxAllocator used for allocating memory * @param string the string to split * @param delim the delimiter string - * @param count IN: the maximum size of the resulting list (0 for an - * unbounded list), OUT: the actual size of the list - * @return a list of the split strings as sstr_t array or + * @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 * <code>NULL</code> on error * * @see sstrsplit() */ sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, - size_t *count); + ssize_t *count); /** * Compares two UCX strings with standard <code>memcmp()</code>. @@ -385,6 +383,56 @@ */ 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
--- a/ucx/test.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/test.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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:
--- a/ucx/test.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/test.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -84,8 +84,8 @@ /** * Alias for the <code>__func__</code> preprocessor macro. - * Some compilers use <code>__func__</code> and others use __FUNC__. - * We use __FUNC__ so we define it for those compilers which use + * Some compilers use <code>__func__</code> and others use __FUNCTION__. + * We use __FUNCTION__ so we define it for those compilers which use * <code>__func__</code>. */ #define __FUNCTION__ __func__
--- a/ucx/ucx.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/ucx.c Mon May 23 12:28:32 2016 +0200 @@ -9,7 +9,7 @@ * * <h2>LICENCE</h2> * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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:
--- a/ucx/ucx.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/ucx.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -37,10 +37,10 @@ #define UCX_H /** Major UCX version as integer constant. */ -#define UCX_VERSION_MAJOR 1 +#define UCX_VERSION_MAJOR 0 /** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 0 +#define UCX_VERSION_MINOR 9 /** The UCX version in format [major].[minor] */ #define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR @@ -70,6 +70,14 @@ /** 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.
--- a/ucx/utils.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/utils.c Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -54,18 +54,22 @@ return 0; } + char *lbuf; size_t ncp = 0; - if (!buf) { - buf = (char*)malloc(bufsize); - if(buf == NULL) { + + if(buf) { + lbuf = buf; + } else { + lbuf = (char*)malloc(bufsize); + if(lbuf == NULL) { return 0; } } size_t r; size_t rn = bufsize > n ? n : bufsize; - while((r = readfnc(buf, 1, rn, src)) != 0) { - r = writefnc(buf, 1, r, dest); + while((r = readfnc(lbuf, 1, rn, src)) != 0) { + r = writefnc(lbuf, 1, r, dest); ncp += r; n -= r; rn = bufsize > n ? n : bufsize; @@ -74,7 +78,10 @@ } } - free(buf); + if (lbuf != buf) { + free(lbuf); + } + return ncp; } @@ -121,10 +128,12 @@ } int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) { - if (ptr1 == ptr2) { + intptr_t p1 = (intptr_t) ptr1; + intptr_t p2 = (intptr_t) ptr2; + if (p1 == p2) { return 0; } else { - return ptr1 < ptr2 ? -1 : 1; + return p1 < p2 ? -1 : 1; } } @@ -212,30 +221,36 @@ va_copy(ap2, ap); int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)a->malloc(a->pool, ret + 1); - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; + s.ptr = (char*)almalloc(a, ret + 1); + if (s.ptr) { + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } } else if (ret == INT_MAX) { errno = ENOMEM; } else { int len = ret + 1; - s.ptr = (char*)a->malloc(a->pool, len); - ret = vsnprintf(s.ptr, len, fmt, ap2); - if (ret < 0) { - free(s.ptr); - s.ptr = NULL; - } else { - s.length = (size_t)ret; + s.ptr = (char*)almalloc(a, len); + if (s.ptr) { + ret = vsnprintf(s.ptr, len, fmt, ap2); + if (ret < 0) { + free(s.ptr); + s.ptr = NULL; + } else { + s.length = (size_t)ret; + } } } #else int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)a->malloc(a->pool, ret + 1); - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; + s.ptr = (char*)almalloc(a, ret + 1); + if (s.ptr) { + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } } else { errno = ENOMEM; }
--- a/ucx/utils.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ucx/utils.h Mon May 23 12:28:32 2016 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 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: @@ -219,6 +219,10 @@ */ sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); +/** Shortcut for ucx_asprintf() with default allocator. */ +#define ucx_sprintf(fmt, ...) \ + ucx_asprintf(ucx_default_allocator(), fmt, __VA_ARGS__) + /** * <code>va_list</code> version of ucx_asprintf(). *
--- a/ui/gtk/model.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ui/gtk/model.c Mon May 23 12:28:32 2016 +0200 @@ -105,14 +105,14 @@ return G_TYPE_INVALID; } -static void ui_model_set_value(UiModelType type, void *data, GValue *value) { +static void ui_model_set_value(GType type, void *data, GValue *value) { switch(type) { - case UI_STRING: { + case G_TYPE_STRING: { value->g_type = G_TYPE_STRING; g_value_set_string(value, data); return; } - case UI_INTEGER: { + case G_TYPE_INT: { value->g_type = G_TYPE_INT; int *i = data; g_value_set_int(value, *i); @@ -126,11 +126,20 @@ UiListModel *model = g_object_new(list_model_type, NULL); model->info = info; model->list = list; - model->columntypes = malloc(sizeof(GType)); - model->numcolumns = info->columns; + model->columntypes = calloc(sizeof(GType), 2 * info->columns); + int ncol = 0; for(int i=0;i<info->columns;i++) { - model->columntypes[i] = ui_gtk_type(info->types[i]); + UiModelType type = info->types[i]; + if(type == UI_ICON_TEXT) { + model->columntypes[ncol] = G_TYPE_STRING; + ncol++; + model->columntypes[ncol] = G_TYPE_STRING; + } else { + model->columntypes[ncol] = ui_gtk_type(info->types[i]); + } + ncol++; } + model->numcolumns = ncol; return model; } @@ -237,7 +246,7 @@ //list->current = iter->user_data3; if(model->info->getvalue) { void *data = model->info->getvalue(iter->user_data3, column); - ui_model_set_value(model->info->types[column], data, value); + ui_model_set_value(model->columntypes[column], data, value); } else { value->g_type = G_TYPE_INVALID; }
--- a/ui/gtk/tree.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ui/gtk/tree.c Mon May 23 12:28:32 2016 +0200 @@ -134,14 +134,33 @@ UIWIDGET ui_table_var(UiObject *obj, UiListPtr *list, UiModelInfo *modelinfo) { // create treeview GtkWidget *view = gtk_tree_view_new(); + int addi = 0; for(int i=0;i<modelinfo->columns;i++) { - GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( + GtkTreeViewColumn *column = NULL; + if(modelinfo->types[i] == UI_ICON_TEXT) { + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, modelinfo->titles[i]); + + GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new(); + GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new(); + + gtk_tree_view_column_pack_end(column, textrenderer, TRUE); + gtk_tree_view_column_pack_start(column, iconrenderer, FALSE); + + + gtk_tree_view_column_add_attribute(column, iconrenderer, "icon-name", i); + gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1); + + addi++; + } else { + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( modelinfo->titles[i], renderer, "text", - i, + i + addi, NULL); + } gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); }
--- a/ui/motif/container.c Tue Feb 16 17:39:33 2016 +0100 +++ b/ui/motif/container.c Mon May 23 12:28:32 2016 +0200 @@ -320,6 +320,27 @@ ucx_list_free(rowdim); } +UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) { + UiContainer *ct = ucx_mempool_calloc( + obj->ctx->mempool, + 1, + sizeof(UiContainer)); + ct->widget = scrolledwindow; + ct->prepare = ui_scrolledwindow_container_prepare; + ct->add = ui_scrolledwindow_container_add; + return ct; +} + +Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { + return ct->widget; +} + +void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget) { + ui_reset_layout(ct->layout); + ct->current = widget; +} + + UiContainer* ui_tabview_container(UiObject *obj, Widget frame) { UiTabViewContainer *ct = ucx_mempool_calloc( obj->ctx->mempool, @@ -413,6 +434,25 @@ return grid; } +UIWIDGET ui_scrolledwindow(UiObject *obj) { + UiContainer *ct = uic_get_current_container(obj); + + Arg args[16]; + int n = 0; + XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); // TODO: dosn't work, use XmAPPLICATION_DEFINED + n++; + Widget parent = ct->prepare(ct, args, &n, TRUE); + Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", args, n); + ct->add(ct, scrolledwindow); + XtManageChild(scrolledwindow); + + UiObject *newobj = uic_object_new(obj, scrolledwindow); + newobj->container = ui_scrolledwindow_container(obj, scrolledwindow); + uic_obj_add(obj, newobj); + + return scrolledwindow; +} + UIWIDGET ui_sidebar(UiObject *obj) { UiContainer *ct = uic_get_current_container(obj);
--- a/ui/motif/container.h Tue Feb 16 17:39:33 2016 +0100 +++ b/ui/motif/container.h Mon May 23 12:28:32 2016 +0200 @@ -136,6 +136,10 @@ Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); void ui_grid_container_add(UiContainer *ct, Widget widget); +UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow); +Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); +void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget); + UiContainer* ui_tabview_container(UiObject *obj, Widget rowcolumn); Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); void ui_tabview_container_add(UiContainer *ct, Widget widget);