# HG changeset patch # User Olaf Wintermann # Date 1516533189 -3600 # Node ID 62921b370c608c483a021c8fb4a699e5eee65dcd # Parent 11f3bb408051372c8e4700a602fa7b91a4da4c60 fixes use after free when a GtkTreeView was destroyed diff -r 11f3bb408051 -r 62921b370c60 application/main.c --- a/application/main.c Wed Nov 22 12:59:13 2017 +0100 +++ b/application/main.c Sun Jan 21 12:13:09 2018 +0100 @@ -149,7 +149,7 @@ } void application_startup(UiEvent *event, void *data) { - UiIcon *icon = ui_icon("gnome-folder", 16); + UiIcon *icon = ui_icon("folder", 16); img = ui_icon_image(icon); if(!img) { fprintf(stderr, "Cannot load folder icon\n"); diff -r 11f3bb408051 -r 62921b370c60 ucx/allocator.c --- a/ucx/allocator.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/allocator.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/allocator.h --- a/ucx/allocator.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/allocator.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,7 +28,7 @@ /** * Allocator for custom memory management. * - * An UCX allocator consists of a pointer to the memory area / pool and four + * A UCX allocator consists of a pointer to the memory area / pool and four * function pointers to memory management functions operating on this memory * area / pool. These functions shall behave equivalent to the standard libc * functions malloc(), calloc(), realloc() and free(). @@ -38,7 +38,7 @@ * memory area / pool as first argument. * * As the pointer to the memory area / pool can be arbitrarily chosen, any data - * can be provided to the memory management functions. An UcxMempool is just + * can be provided to the memory management functions. A UcxMempool is just * one example. * * @see mempool.h @@ -116,7 +116,7 @@ * management functions. Use this function to get a pointer to a globally * available allocator. You may also define an own UcxAllocator by assigning * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable - * to any function that takes an UcxAllocator as argument. Note that using + * to any function that takes a UcxAllocator as argument. Note that using * this function is the recommended way of passing a default allocator, thus * it never runs out of scope. * diff -r 11f3bb408051 -r 62921b370c60 ucx/avl.c --- a/ucx/avl.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/avl.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -26,9 +26,13 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include + #include "avl.h" #define ptrcast(ptr) ((void*)(ptr)) +#define alloc_tree(al) (UcxAVLTree*) almalloc((al), sizeof(UcxAVLTree)) +#define alloc_node(al) (UcxAVLNode*) almalloc((al), sizeof(UcxAVLNode)) static void ucx_avl_connect(UcxAVLTree *tree, UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) { @@ -107,7 +111,7 @@ } UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) { - UcxAVLTree *tree = almalloc(allocator, sizeof(UcxAVLTree)); + UcxAVLTree* tree = alloc_tree(allocator); if (tree) { tree->allocator = allocator; tree->cmpfunc = cmpfunc; @@ -147,6 +151,46 @@ return n ? n->value : NULL; } +UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode) { + UcxAVLNode *n = tree->root; + UcxAVLNode *closest = NULL; + + intmax_t cmpresult; + intmax_t closest_dist; + closest_dist = mode == UCX_AVL_FIND_LOWER_BOUNDED ? INTMAX_MIN : INTMAX_MAX; + + while (n && (cmpresult = dfnc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + if (mode == UCX_AVL_FIND_CLOSEST) { + intmax_t dist = cmpresult; + if (dist < 0) dist *= -1; + if (dist < closest_dist) { + closest_dist = dist; + closest = n; + } + } else if (mode == UCX_AVL_FIND_LOWER_BOUNDED && cmpresult <= 0) { + if (cmpresult > closest_dist) { + closest_dist = cmpresult; + closest = n; + } + } else if (mode == UCX_AVL_FIND_UPPER_BOUNDED && cmpresult >= 0) { + if (cmpresult < closest_dist) { + closest_dist = cmpresult; + closest = n; + } + } + n = cmpresult > 0 ? n->right : n->left; + } + return n ? n : closest; +} + +void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode) { + UcxAVLNode *n = ucx_avl_find_node(tree, key, dfnc, mode); + return n ? n->value : NULL; +} + int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) { return ucx_avl_put_s(tree, key, value, NULL); } @@ -167,7 +211,7 @@ } if (cmpresult) { - UcxAVLNode *e = almalloc(tree->allocator, sizeof(UcxAVLNode)); + UcxAVLNode* e = alloc_node(tree->allocator); if (e) { e->key = key; e->value = value; e->height = 1; e->parent = e->left = e->right = NULL; @@ -185,7 +229,7 @@ return 0; } } else { - tree->root = almalloc(tree->allocator, sizeof(UcxAVLNode)); + tree->root = alloc_node(tree->allocator); if (tree->root) { tree->root->key = key; tree->root->value = value; tree->root->height = 1; @@ -270,3 +314,43 @@ size_t ucx_avl_count(UcxAVLTree *tree) { return ucx_avl_countn(tree->root); } + +UcxAVLNode* ucx_avl_pred(UcxAVLNode* node) { + if (node->left) { + UcxAVLNode* n = node->left; + while (n->right) { + n = n->right; + } + return n; + } else { + UcxAVLNode* n = node; + while (n->parent) { + if (n->parent->right == n) { + return n->parent; + } else { + n = n->parent; + } + } + return NULL; + } +} + +UcxAVLNode* ucx_avl_succ(UcxAVLNode* node) { + if (node->right) { + UcxAVLNode* n = node->right; + while (n->left) { + n = n->left; + } + return n; + } else { + UcxAVLNode* n = node; + while (n->parent) { + if (n->parent->left == n) { + return n->parent; + } else { + n = n->parent; + } + } + return NULL; + } +} diff -r 11f3bb408051 -r 62921b370c60 ucx/avl.h --- a/ucx/avl.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/avl.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,7 +44,7 @@ #include "ucx.h" #include "allocator.h" -#include +#include #ifdef __cplusplus extern "C" { @@ -134,7 +134,7 @@ UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator); /** - * Destroys an UcxAVLTree. + * Destroys a UcxAVLTree. * @param tree the tree to destroy */ void ucx_avl_free(UcxAVLTree *tree); @@ -164,6 +164,68 @@ void *ucx_avl_get(UcxAVLTree *tree, intptr_t key); /** + * A mode for #ucx_avl_find_node() with the same behavior as + * #ucx_avl_get_node(). + */ +#define UCX_AVL_FIND_EXACT 0 +/** + * A mode for #ucx_avl_find_node() finding the node whose key is at least + * as large as the specified key. + */ +#define UCX_AVL_FIND_LOWER_BOUNDED 1 +/** + * A mode for #ucx_avl_find_node() finding the node whose key is at most + * as large as the specified key. + */ +#define UCX_AVL_FIND_UPPER_BOUNDED 2 +/** + * A mode for #ucx_avl_find_node() finding the node with a key that is as close + * to the specified key as possible. If the key is present, the behavior is + * like #ucx_avl_get_node(). This mode only returns NULL on + * empty trees. + */ +#define UCX_AVL_FIND_CLOSEST 3 + +/** + * Finds a node within the tree. The following modes are supported: + *
    + *
  • #UCX_AVL_FIND_EXACT: the same behavior as #ucx_avl_get_node()
  • + *
  • #UCX_AVL_FIND_LOWER_BOUNDED: finds the node whose key is at least + * as large as the specified key
  • + *
  • #UCX_AVL_FIND_UPPER_BOUNDED: finds the node whose key is at most + * as large as the specified key
  • + *
  • #UCX_AVL_FIND_CLOSEST: finds the node with a key that is as close to + * the specified key as possible. If the key is present, the behavior is + * like #ucx_avl_get_node(). This mode only returns NULL on + * empty trees.
  • + *
+ * + * The distance function provided MUST agree with the compare function of + * the AVL tree. + * + * @param tree the UcxAVLTree + * @param key the key + * @param dfnc the distance function + * @param mode the find mode + * @return the node (or NULL, if no node can be found) + */ +UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode); + +/** + * Finds a value within the tree. + * See #ucx_avl_find_node() for details. + * + * @param tree the UcxAVLTree + * @param key the key + * @param dfnc the distance function + * @param mode the find mode + * @return the value (or NULL, if no value can be found) + */ +void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode); + +/** * Puts a key/value pair into the tree. * * Attention: use this function only, if a possible old value does not need @@ -196,7 +258,7 @@ * * 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. + * is freed, so its further use is generally undefined. * * @param tree the UcxAVLTree * @param node the node to remove @@ -241,6 +303,22 @@ */ size_t ucx_avl_count(UcxAVLTree *tree); +/** + * Finds the in-order predecessor of the given node. + * @param node an AVL node + * @return the in-order predecessor of the given node, or NULL if + * the given node is the in-order minimum + */ +UcxAVLNode* ucx_avl_pred(UcxAVLNode* node); + +/** + * Finds the in-order successor of the given node. + * @param node an AVL node + * @return the in-order successor of the given node, or NULL if + * the given node is the in-order maximum + */ +UcxAVLNode* ucx_avl_succ(UcxAVLNode* node); + #ifdef __cplusplus } #endif diff -r 11f3bb408051 -r 62921b370c60 ucx/buffer.c --- a/ucx/buffer.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/buffer.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -150,6 +150,7 @@ size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, UcxBuffer *buffer) { size_t len = size * nitems; + const char *string = ptr; size_t required = buffer->pos + len; if (buffer->pos > required) { return 0; diff -r 11f3bb408051 -r 62921b370c60 ucx/buffer.h --- a/ucx/buffer.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/buffer.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -197,9 +197,9 @@ int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); /** - * Writes data to an UcxBuffer. + * Writes data to a UcxBuffer. * - * The position of the buffer is increased by the number of bytes read. + * The position of the buffer is increased by the number of bytes written. * * @param ptr a pointer to the memory area containing the bytes to be written * @param size the length of one element @@ -211,7 +211,7 @@ UcxBuffer *buffer); /** - * Reads data from an UcxBuffer. + * Reads data from a UcxBuffer. * * The position of the buffer is increased by the number of bytes read. * diff -r 11f3bb408051 -r 62921b370c60 ucx/list.c --- a/ucx/list.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/list.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -76,6 +76,13 @@ } } +void ucx_list_free_content(UcxList* list, ucx_destructor destr) { + while (list != NULL) { + destr(list->data); + list = list->next; + } +} + UcxList *ucx_list_append(UcxList *l, void *data) { return ucx_list_append_a(ucx_default_allocator(), l, data); } @@ -99,6 +106,41 @@ } } +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 11f3bb408051 -r 62921b370c60 ucx/list.h --- a/ucx/list.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/list.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -46,13 +46,13 @@ /** * Loop statement for UCX lists. * - * The first argument is a pointer to the list. In most cases this will be the + * The first argument is the name of the iteration variable. The scope of + * this variable is limited to the UCX_FOREACH statement. + * + * The second argument is a pointer to the list. In most cases this will be the * pointer to the first element of the list, but it may also be an arbitrary * element of the list. The iteration will then start with that element. * - * The second argument is the name of the iteration variable. The scope of - * this variable is limited to the UCX_FOREACH statement. - * * @param list The first element of the list * @param elem The variable name of the element */ @@ -102,13 +102,12 @@ UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); /** - * Creates an element-wise copy of a list using an UcxAllocator. + * Creates an element-wise copy of a list using a UcxAllocator. * * See ucx_list_clone() for details. * - * Keep in mind, that you might want to pass the allocator as an (part of the) - * argument for the data parameter, if you want the copy_func() to - * make use of the allocator. + * You might want to pass the allocator via the data parameter, + * to access it within the copy function for making deep copies. * * @param allocator the allocator to use * @param list the list to copy @@ -146,17 +145,19 @@ * Destroys the entire list. * * The members of the list are not automatically freed, so ensure they are - * otherwise referenced or a memory leak will occur. + * otherwise referenced or destroyed by ucx_list_free_contents(). + * Otherwise, a memory leak is likely to occur. * * Caution: the argument MUST denote an entire list (i.e. a call * to ucx_list_first() on the argument must return the argument itself) * * @param list the list to free + * @see ucx_list_free_contents() */ void ucx_list_free(UcxList *list); /** - * Destroys the entire list using an UcxAllocator. + * Destroys the entire list using a UcxAllocator. * * See ucx_list_free() for details. * @@ -167,6 +168,20 @@ void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); /** + * Destroys the contents of the specified list by calling the specified + * destructor on each of them. + * + * Note, that the contents are not usable afterwards and the list should be + * destroyed with ucx_list_free(). + * + * @param list the list for which the contents shall be freed + * @param destr the destructor function (e.g. stdlib free()) + * @see ucx_list_free() + */ +void ucx_list_free_content(UcxList* list, ucx_destructor destr); + + +/** * Inserts an element at the end of the list. * * This is generally an O(n) operation, as the end of the list is retrieved with @@ -181,7 +196,7 @@ UcxList *ucx_list_append(UcxList *list, void *data); /** - * Inserts an element at the end of the list using an UcxAllocator. + * Inserts an element at the end of the list using a UcxAllocator. * * See ucx_list_append() for details. * @@ -196,6 +211,41 @@ 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. * * You should overwrite the old list pointer by calling @@ -212,7 +262,7 @@ UcxList *ucx_list_prepend(UcxList *list, void *data); /** - * Inserts an element at the beginning of the list using an UcxAllocator. + * Inserts an element at the beginning of the list using a UcxAllocator. * * See ucx_list_prepend() for details. * @@ -327,7 +377,7 @@ int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); /** - * Sorts an UcxList with natural merge sort. + * Sorts a UcxList with natural merge sort. * * This function uses O(n) additional temporary memory for merge operations * that is automatically freed after each merge. @@ -357,7 +407,7 @@ UcxList *ucx_list_remove(UcxList *list, UcxList *element); /** - * Removes an element from the list using an UcxAllocator. + * Removes an element from the list using a UcxAllocator. * * See ucx_list_remove() for details. * diff -r 11f3bb408051 -r 62921b370c60 ucx/logging.c --- a/ucx/logging.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/logging.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/logging.h --- a/ucx/logging.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/logging.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/map.c --- a/ucx/map.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/map.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/map.h --- a/ucx/map.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/map.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -59,7 +59,7 @@ * * @param key the variable name for the key * @param value the variable name for the value - * @param iter an UcxMapIterator + * @param iter a UcxMapIterator * @see ucx_map_iterator() */ #define UCX_MAP_FOREACH(key,value,iter) \ @@ -68,13 +68,13 @@ /** Type for the UCX map. @see UcxMap */ typedef struct UcxMap UcxMap; -/** Type for a key of an UcxMap. @see UcxKey */ +/** Type for a key of a UcxMap. @see UcxKey */ typedef struct UcxKey UcxKey; -/** Type for an element of an UcxMap. @see UcxMapElement */ +/** Type for an element of a UcxMap. @see UcxMapElement */ typedef struct UcxMapElement UcxMapElement; -/** Type for an iterator over an UcxMap. @see UcxMapIterator */ +/** Type for an iterator over a UcxMap. @see UcxMapIterator */ typedef struct UcxMapIterator UcxMapIterator; /** Structure for the UCX map. */ @@ -89,7 +89,7 @@ size_t count; }; -/** Structure for a key of an UcxMap. */ +/** Structure for a key of a UcxMap. */ struct UcxKey { /** The key data. */ void *data; @@ -99,7 +99,7 @@ int hash; }; -/** Structure for an element of an UcxMap. */ +/** Structure for an element of a UcxMap. */ struct UcxMapElement { /** The value data. */ void *data; @@ -111,7 +111,7 @@ UcxKey key; }; -/** Structure for an iterator over an UcxMap. */ +/** Structure for an iterator over a UcxMap. */ struct UcxMapIterator { /** The map to iterate over. */ UcxMap *map; @@ -136,7 +136,7 @@ UcxMap *ucx_map_new(size_t size); /** - * Creates a new hash map with the specified size using an UcxAllocator. + * Creates a new hash map with the specified size using a UcxAllocator. * @param allocator the allocator to use * @param size the size of the hash map * @return a pointer to the new hash map @@ -357,13 +357,13 @@ ucx_map_remove(map, ucx_key((void*)&key, sizeof(key))) /** - * Creates an UcxKey based on the given data. + * Creates a UcxKey based on the given data. * * This function implicitly computes the hash. * * @param data the data for the key * @param len the length of the data - * @return an UcxKey with implicitly computed hash + * @return a UcxKey with implicitly computed hash * @see ucx_hash() */ UcxKey ucx_key(void *data, size_t len); @@ -380,14 +380,14 @@ /** * Creates an iterator for a map. * - * Note: An UcxMapIterator iterates over all elements in all element + * Note: A UcxMapIterator iterates over all elements in all element * lists successively. Therefore the order highly depends on the key hashes and * may vary under different map sizes. So generally you may NOT rely on * the iteration order. * * Note: The iterator is NOT initialized. You need to call * ucx_map_iter_next() at least once before accessing any information. However, - * it is not recommended to access the fields of an UcxMapIterator directly. + * it is not recommended to access the fields of a UcxMapIterator directly. * * @param map the map to create the iterator for * @return an iterator initialized on the first element of the diff -r 11f3bb408051 -r 62921b370c60 ucx/mempool.c --- a/ucx/mempool.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/mempool.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -93,25 +93,30 @@ } int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) { + if (newcap < pool->ndata) { + return 1; + } + void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); if (data) { pool->data = data; pool->size = newcap; - return EXIT_SUCCESS; + return 0; } else { - return EXIT_FAILURE; + return 1; } } void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { if (pool->ndata >= pool->size) { - // The hard coded 16 is documented for this function and ucx_mempool_new - if (ucx_mempool_chcap(pool, pool->size + 16) == EXIT_FAILURE) { + size_t newcap = pool->size*2; + if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) { return NULL; } } - ucx_memchunk *mem = (ucx_memchunk*)malloc(sizeof(ucx_destructor) + n); + void *p = malloc(sizeof(ucx_destructor) + n); + ucx_memchunk *mem = (ucx_memchunk*)p; if (!mem) { return NULL; } @@ -147,7 +152,7 @@ } fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", (intptr_t)ptr, (intptr_t)pool); - exit(EXIT_FAILURE); + abort(); } else { return newm + sizeof(ucx_destructor); } @@ -172,7 +177,7 @@ } fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", (intptr_t)ptr, (intptr_t)pool); - exit(EXIT_FAILURE); + abort(); } void ucx_mempool_destroy(UcxMempool *pool) { diff -r 11f3bb408051 -r 62921b370c60 ucx/mempool.h --- a/ucx/mempool.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/mempool.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -70,39 +70,29 @@ /** * Creates a memory pool with the specified initial size. * - * As the created memory pool automatically grows in size by 16 elements, when + * As the created memory pool automatically grows in size by factor two when * trying to allocate memory on a full pool, it is recommended that you use - * a multiple of 16 for the initial size. + * a power of two for the initial size. * - * @param n initial pool size (should be a multiple of 16) + * @param n initial pool size (should be a power of two, e.g. 16) * @return a pointer to the new memory pool + * @see ucx_mempool_new_default() */ UcxMempool *ucx_mempool_new(size_t n); /** * Resizes a memory pool. * + * This function will fail if the new capacity is not sufficient for the + * present data. + * * @param pool the pool to resize * @param newcap the new capacity - * @return EXIT_SUCCESS on success or - * EXIT_FAILURE on failure + * @return zero on success or non-zero on failure */ int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); /** - * Changes the pool size to the next smallest multiple of 16. - * - * You may use this macro, to reduce the pool size after freeing - * many pooled memory items. - * - * @param pool the pool to clamp - * @return EXIT_SUCCESS on success or - * EXIT_FAILURE on failure - */ -#define ucx_mempool_clamp(pool) ucx_mempool_chcap(pool, \ - (pool->ndata & ~0xF)+0x10) - -/** * Allocates pooled memory. * * @param pool the memory pool @@ -127,10 +117,8 @@ /** * Reallocates pooled memory. * - * If the memory to be reallocated is not contained by the specified pool, this - * function will possibly fail. In case the memory had to be moved to another - * location, this function will print out a message to stderr - * and exit the program with error code EXIT_FAILURE. + * If the memory to be reallocated is not contained by the specified pool, the + * behavior is undefined. * * @param pool the memory pool * @param ptr a pointer to the memory that shall be reallocated @@ -146,10 +134,8 @@ * Before freeing the memory, the specified destructor function (if any) * is called. * - * If you specify memory, that is not pooled by the specified memory pool, this - * is considered as a severe error and an error message is written to - * stderr and the application is shut down with code - * EXIT_FAILURE. + * If you specify memory, that is not pooled by the specified memory pool, the + * program will terminate with a call to abort(). * * @param pool the memory pool * @param ptr a pointer to the memory that shall be freed @@ -180,7 +166,7 @@ * pool is destroyed. * * The only requirement for the specified memory is, that it MUST be - * pooled memory by an UcxMempool or an element-compatible mempool. The pointer + * pooled memory by a UcxMempool or an element-compatible mempool. The pointer * to the destructor function is saved in a reserved area before the actual * memory. * diff -r 11f3bb408051 -r 62921b370c60 ucx/properties.c --- a/ucx/properties.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/properties.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/properties.h --- a/ucx/properties.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/properties.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -127,7 +127,7 @@ UcxProperties *ucx_properties_new(); /** - * Destroys an UcxProperties object. + * Destroys a UcxProperties object. * @param prop the UcxProperties object to destroy */ void ucx_properties_free(UcxProperties *prop); @@ -137,8 +137,8 @@ * * After calling this function, you may parse the data by calling * ucx_properties_next() until it returns 0. The function ucx_properties2map() - * is a convenience function that performs these successive calls of - * ucx_properties_next() within a while loop and puts the properties to a map. + * is a convenience function that reads as much data as possible by using this + * function. * * * @param prop the UcxProperties object @@ -170,7 +170,7 @@ int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value); /** - * Retrieves all available key/value-pairs and puts them into an UcxMap. + * 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. @@ -183,13 +183,11 @@ int ucx_properties2map(UcxProperties *prop, UcxMap *map); /** - * Loads a properties file to an UcxMap. + * Loads a properties file to a UcxMap. * - * This is a convenience function that reads chunks of 1 KB from an input + * This is a convenience function that reads data from an input * stream until the end of the stream is reached. * - * An UcxProperties object is implicitly created and destroyed. - * * @param map the map object to write the key/value-pairs to * @param file the FILE* stream to read from * @return 0 on success, or a non-zero value on error @@ -200,7 +198,7 @@ int ucx_properties_load(UcxMap *map, FILE *file); /** - * Stores an UcxMap to a file. + * Stores a UcxMap to a file. * * The key/value-pairs are written by using the following format: * diff -r 11f3bb408051 -r 62921b370c60 ucx/stack.c --- a/ucx/stack.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/stack.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/stack.h --- a/ucx/stack.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/stack.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,7 +39,6 @@ #define UCX_STACK_H #include "ucx.h" -#include #include "allocator.h" #ifdef __cplusplus @@ -179,7 +178,7 @@ * @see ucx_stack_free * @see ucx_stack_popn */ -#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, SIZE_MAX) +#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, (size_t)-1) /** * Removes the top most element from the stack and copies the content to diff -r 11f3bb408051 -r 62921b370c60 ucx/string.c --- a/ucx/string.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/string.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "string.h" @@ -175,6 +176,79 @@ return n; } +#define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \ + ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index]) + +#define ptable_w(useheap, ptable, index, src) do {\ + if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\ + else ((size_t*)ptable)[index] = src;\ + } while (0); + +sstr_t sstrstr(sstr_t string, sstr_t match) { + if (match.length == 0) { + return string; + } + + /* prepare default return value in case of no match */ + sstr_t result = sstrn(NULL, 0); + + /* + * IMPORTANT: + * our prefix table contains the prefix length PLUS ONE + * this is our decision, because we want to use the full range of size_t + * the original algorithm needs a (-1) at one single place + * and we want to avoid that + */ + + /* static prefix table */ + static uint8_t s_prefix_table[256]; + + /* check pattern length and use appropriate prefix table */ + /* if the pattern exceeds static prefix table, allocate on the heap */ + register int useheap = match.length > 255; + register void* ptable = useheap ? + calloc(match.length+1, sizeof(size_t)): s_prefix_table; + + /* keep counter in registers */ + register size_t i, j; + + /* fill prefix table */ + i = 0; j = 0; + ptable_w(useheap, ptable, i, j); + while (i < match.length) { + while (j >= 1 && match.ptr[j-1] != match.ptr[i]) { + ptable_r(j, useheap, ptable, j-1); + } + i++; j++; + ptable_w(useheap, ptable, i, j); + } + + /* search */ + i = 0; j = 1; + while (i < string.length) { + while (j >= 1 && string.ptr[i] != match.ptr[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; + break; + } + } + + /* if prefix table was allocated on the heap, free it */ + if (ptable != s_prefix_table) { + free(ptable); + } + + 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); } @@ -184,70 +258,85 @@ *n = -1; return NULL; } - - sstr_t* result; - ssize_t nmax = *n; - *n = 1; - - /* special case: exact match - no processing needed */ - if (sstrcmp(s, d) == 0) { - *n = 0; - return NULL; + + /* special cases: delimiter is at least as large as the string */ + if (d.length >= s.length) { + /* exact match */ + if (sstrcmp(s, d) == 0) { + *n = 0; + return NULL; + } else /* no match possible */ { + *n = 1; + sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)); + *result = sstrdup_a(allocator, s); + return result; + } } - sstr_t sv = sstrdup(s); - if (sv.length == 0) { - *n = -2; - return NULL; - } + + ssize_t nmax = *n; + size_t arrlen = 16; + sstr_t* result = (sstr_t*) almalloc(allocator, arrlen*sizeof(sstr_t)); - for (size_t i = 0 ; i < s.length ; i++) { - if (sv.ptr[i] == d.ptr[0]) { - _Bool match = 1; - for (size_t j = 1 ; j < d.length ; j++) { - if (j+i < s.length) { - match &= (sv.ptr[i+j] == d.ptr[j]); + if (result) { + sstr_t curpos = s; + ssize_t j = 1; + while (1) { + sstr_t match; + /* optimize for one byte delimiters */ + if (d.length == 1) { + match = curpos; + for (size_t i = 0 ; i < curpos.length ; i++) { + if (curpos.ptr[i] == *(d.ptr)) { + match.ptr = curpos.ptr + i; + break; + } + match.length--; + } + } else { + match = sstrstr(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); + result[j-1] = sstrdup_a(allocator, item); + size_t processed = item.length + d.length; + curpos.ptr += processed; + curpos.length -= processed; + + /* allocate memory for the next string */ + j++; + if (j > arrlen) { + arrlen *= 2; + sstr_t* reallocated = (sstr_t*) alrealloc( + allocator, result, arrlen*sizeof(sstr_t)); + if (reallocated) { + result = reallocated; + } else { + for (ssize_t i = 0 ; i < j-1 ; i++) { + alfree(allocator, result[i].ptr); + } + alfree(allocator, result); + *n = -2; + return NULL; + } + } } else { - match = 0; + /* nmax reached, copy the _full_ remaining string */ + result[j-1] = sstrdup_a(allocator, curpos); break; } - } - if (match) { - (*n)++; - for (size_t j = 0 ; j < d.length ; j++) { - sv.ptr[i+j] = 0; - } - i += d.length; - } - } - if ((*n) == nmax) break; - } - result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)*(*n)); - - if (result) { - char *pptr = sv.ptr; - for (ssize_t i = 0 ; i < *n ; i++) { - size_t l = strlen(pptr); - char* ptr = (char*) almalloc(allocator, l + 1); - if (ptr) { - memcpy(ptr, pptr, l); - ptr[l] = 0; - - 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; + /* no more matches, copy last string */ + result[j-1] = sstrdup_a(allocator, curpos); break; } } + *n = j; } else { *n = -2; } - - free(sv.ptr); return result; } diff -r 11f3bb408051 -r 62921b370c60 ucx/string.h --- a/ucx/string.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/string.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -137,7 +137,7 @@ sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); /** - * Concatenates two or more strings using an UcxAllocator. + * Concatenates two or more strings using a UcxAllocator. * * See sstrcat() for details. * @@ -214,6 +214,23 @@ sstr_t sstrrchr(sstr_t string, int chr); /** + * Returns a substring starting at the location of the first occurrence of the + * specified string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. + * + * @param string the string to be scanned + * @param match string containing the sequence of characters to match + * @return a substring starting at the first occurrence of + * match, or an empty string, if the sequence is not + * present in string + */ +sstr_t sstrstr(sstr_t string, sstr_t match); + +/** * Splits a string into parts by using a delimiter string. * * This function will return NULL, if one of the following happens: @@ -243,6 +260,9 @@ * * If the string ends with the delimiter and the maximum list size is not * exceeded, the last array item will be an empty string. + * In case the list size would be exceeded, the last array item will be the + * remaining string after the last split, including the terminating + * delimiter. * * Attention: The array pointer AND all sstr_t.ptr of the array * items must be manually passed to free(). Use sstrsplit_a() with @@ -260,7 +280,7 @@ sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); /** - * Performing sstrsplit() using an UcxAllocator. + * Performing sstrsplit() using a UcxAllocator. * * Read the description of sstrsplit() for details. * @@ -331,7 +351,7 @@ sstr_t sstrdup(sstr_t string); /** - * Creates a duplicate of the specified string using an UcxAllocator. + * 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 @@ -341,7 +361,7 @@ * The sstr_t.ptr of the return value will always be NULL- * terminated. * - * @param allocator a valid instance of an UcxAllocator + * @param allocator a valid instance of a UcxAllocator * @param string the string to duplicate * @return a duplicate of the string * @see sstrdup() diff -r 11f3bb408051 -r 62921b370c60 ucx/test.c --- a/ucx/test.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/test.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -86,6 +86,6 @@ elem->test(suite, output); } fwrite("\nAll test completed.\n", 1, 21, output); - fprintf(output, " Total: %d\n Success: %d\n Failure: %d\n", + fprintf(output, " Total: %u\n Success: %u\n Failure: %u\n", suite->success+suite->failure, suite->success, suite->failure); } diff -r 11f3bb408051 -r 62921b370c60 ucx/test.h --- a/ucx/test.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/test.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -160,7 +160,7 @@ /** * Macro for a #UcxTest function header. * - * Use this macro to declare and/or define an #UcxTest function. + * Use this macro to declare and/or define a #UcxTest function. * * @param name the name of the test function */ @@ -196,7 +196,7 @@ /** * Macro for a test subroutine function header. * - * Use this to declare and/or define an subroutine that can be called by using + * Use this to declare and/or define a subroutine that can be called by using * UCX_TEST_CALL_SUBROUTINE(). * * @param name the name of the subroutine diff -r 11f3bb408051 -r 62921b370c60 ucx/ucx.c --- a/ucx/ucx.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/ucx.c Sun Jan 21 12:13:09 2018 +0100 @@ -9,7 +9,7 @@ * *

LICENCE

* - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 11f3bb408051 -r 62921b370c60 ucx/ucx.h --- a/ucx/ucx.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/ucx.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,12 +40,10 @@ #define UCX_VERSION_MAJOR 0 /** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 9 - -/** The UCX version in format [major].[minor] */ -#define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR +#define UCX_VERSION_MINOR 12 #include +#include #ifdef _WIN32 #if !(defined __ssize_t_defined || defined _SSIZE_T_) @@ -89,7 +87,16 @@ * and 0 if both arguments are equal. If the third argument is * NULL, it shall be ignored. */ -typedef int(*cmp_func)(void*,void*,void*); +typedef int(*cmp_func)(const void*,const void*,void*); + +/** + * Function pointer to a distance function. + * + * The distance function shall take three arguments: the two values for which + * the distance shall be computed and optional additional data. + * The function shall then return the signed distance as integer value. + */ +typedef intmax_t(*distance_func)(const void*,const void*,void*); /** * Function pointer to a copy function. @@ -102,7 +109,7 @@ * passed to free() depends on the implementation of the * respective copy_func. */ -typedef void*(*copy_func)(void*,void*); +typedef void*(*copy_func)(const void*,void*); /** * Function pointer to a write function. diff -r 11f3bb408051 -r 62921b370c60 ucx/utils.c --- a/ucx/utils.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/utils.c Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,22 +33,22 @@ #include /* COPY FUCNTIONS */ -void* ucx_strcpy(void* s, void* data) { - char *str = (char*) s; +void* ucx_strcpy(const void* s, void* data) { + const char *str = (const char*) s; size_t n = 1+strlen(str); char *cpy = (char*) malloc(n); memcpy(cpy, str, n); return cpy; } -void* ucx_memcpy(void* m, void* n) { +void* ucx_memcpy(const void* m, void* n) { size_t k = *((size_t*)n); void *cpy = malloc(k); memcpy(cpy, m, k); return cpy; } -size_t ucx_stream_copy(void *src, void *dest, read_func readfnc, +size_t ucx_stream_bncopy(void *src, void *dest, read_func readfnc, write_func writefnc, char* buf, size_t bufsize, size_t n) { if(n == 0 || bufsize == 0) { return 0; @@ -87,17 +87,17 @@ /* COMPARE FUNCTIONS */ -int ucx_strcmp(void *s1, void *s2, void *data) { - return strcmp((char*)s1, (char*)s2); +int ucx_strcmp(const void *s1, const void *s2, void *data) { + return strcmp((const char*)s1, (const char*)s2); } -int ucx_strncmp(void *s1, void *s2, void *n) { - return strncmp((char*)s1, (char*)s2, *((size_t*) n)); +int ucx_strncmp(const void *s1, const void *s2, void *n) { + return strncmp((const char*)s1, (const char*)s2, *((size_t*) n)); } -int ucx_intcmp(void *i1, void *i2, void *data) { - int a = *((int*) i1); - int b = *((int*) i2); +int ucx_intcmp(const void *i1, const void *i2, void *data) { + int a = *((const int*) i1); + int b = *((const int*) i2); if (a == b) { return 0; } else { @@ -105,9 +105,9 @@ } } -int ucx_floatcmp(void *f1, void *f2, void *epsilon) { - float a = *((float*) f1); - float b = *((float*) f2); +int ucx_floatcmp(const void *f1, const void *f2, void *epsilon) { + float a = *((const float*) f1); + float b = *((const float*) f2); float e = !epsilon ? 1e-6f : *((float*)epsilon); if (fabsf(a - b) < e) { return 0; @@ -116,9 +116,9 @@ } } -int ucx_doublecmp(void *d1, void *d2, void *epsilon) { - double a = *((float*) d1); - double b = *((float*) d2); +int ucx_doublecmp(const void *d1, const void *d2, void *epsilon) { + double a = *((const double*) d1); + double b = *((const double*) d2); double e = !epsilon ? 1e-14 : *((double*)epsilon); if (fabs(a - b) < e) { return 0; @@ -127,9 +127,9 @@ } } -int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) { - intptr_t p1 = (intptr_t) ptr1; - intptr_t p2 = (intptr_t) ptr2; +int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data) { + const intptr_t p1 = (const intptr_t) ptr1; + const intptr_t p2 = (const intptr_t) ptr2; if (p1 == p2) { return 0; } else { @@ -137,7 +137,7 @@ } } -int ucx_memcmp(void *ptr1, void *ptr2, void *n) { +int ucx_memcmp(const void *ptr1, const void *ptr2, void *n) { return memcmp(ptr1, ptr2, *((size_t*)n)); } diff -r 11f3bb408051 -r 62921b370c60 ucx/utils.h --- a/ucx/utils.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ucx/utils.h Sun Jan 21 12:13:09 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2015 Olaf Wintermann. All rights reserved. + * Copyright 2016 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,17 +45,22 @@ #include "ucx.h" #include "string.h" #include "allocator.h" -#include +#include #include #include /** + * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy(). + */ +#define UCX_STREAM_COPY_BUFSIZE 4096 + +/** * Copies a string. * @param s the string to copy * @param data omitted * @return a pointer to a copy of s1 that can be passed to free(void*) */ -void *ucx_strcpy(void *s, void *data); +void *ucx_strcpy(const void *s, void *data); /** * Copies a memory area. @@ -64,7 +69,7 @@ * @return a pointer to a copy of the specified memory area that can * be passed to free(void*) */ -void *ucx_memcpy(void *m, void *n); +void *ucx_memcpy(const void *m, void *n); /** @@ -82,23 +87,26 @@ * @param n the maximum number of bytes that shall be copied * @return the total number of bytes copied */ -size_t ucx_stream_copy(void *src, void *dest, read_func rfnc, write_func wfnc, +size_t ucx_stream_bncopy(void *src, void *dest, read_func rfnc, write_func wfnc, char* buf, size_t bufsize, size_t n); /** - * Shorthand for ucx_stream_copy using the default copy buffer. + * Shorthand for an unbounded ucx_stream_bncopy call using a default buffer. * * @param src the source stream * @param dest the destination stream * @param rfnc the read function * @param wfnc the write function * @return total number of bytes copied + * + * @see #UCX_STREAM_COPY_BUFSIZE */ -#define ucx_stream_hcopy(src,dest,rfnc,wfnc) ucx_stream_copy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, SIZE_MAX) +#define ucx_stream_copy(src,dest,rfnc,wfnc) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + NULL, UCX_STREAM_COPY_BUFSIZE, (size_t)-1) /** - * Shorthand for ucx_stream_copy using the default copy buffer and a copy limit. + * Shorthand for ucx_stream_bncopy using a default copy buffer. * * @param src the source stream * @param dest the destination stream @@ -107,8 +115,27 @@ * @param n maximum number of bytes that shall be copied * @return total number of bytes copied */ -#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_copy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, n) +#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + NULL, UCX_STREAM_COPY_BUFSIZE, n) + +/** + * Shorthand for an unbounded ucx_stream_bncopy call using the specified buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or NULL if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if NULL was + * provided for buf, this is the size of the buffer that shall be + * implicitly created + * @return total number of bytes copied + */ +#define ucx_stream_bcopy(src,dest,rfnc,wfnc, buf, bufsize) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + buf, bufsize, (size_t)-1) /** * Wraps the strcmp function. @@ -117,7 +144,7 @@ * @param data omitted * @return the result of strcmp(s1, s2) */ -int ucx_strcmp(void *s1, void *s2, void *data); +int ucx_strcmp(const void *s1, const void *s2, void *data); /** * Wraps the strncmp function. @@ -126,7 +153,7 @@ * @param n a pointer to the size_t containing the third strncmp parameter * @return the result of strncmp(s1, s2, *n) */ -int ucx_strncmp(void *s1, void *s2, void *n); +int ucx_strncmp(const void *s1, const void *s2, void *n); /** * Compares two integers of type int. @@ -136,7 +163,7 @@ * @return -1, if *i1 is less than *i2, 0 if both are equal, * 1 if *i1 is greater than *i2 */ -int ucx_intcmp(void *i1, void *i2, void *data); +int ucx_intcmp(const void *i1, const void *i2, void *data); /** * Compares two real numbers of type float. @@ -147,7 +174,7 @@ * 1 if *f1 is greater than *f2 */ -int ucx_floatcmp(void *f1, void *f2, void *data); +int ucx_floatcmp(const void *f1, const void *f2, void *data); /** * Compares two real numbers of type double. @@ -157,7 +184,7 @@ * @return -1, if *d1 is less than *d2, 0 if both are equal, * 1 if *d1 is greater than *d2 */ -int ucx_doublecmp(void *d1, void *d2, void *data); +int ucx_doublecmp(const void *d1, const void *d2, void *data); /** * Compares two pointers. @@ -167,7 +194,7 @@ * @return -1 if ptr1 is less than ptr2, 0 if both are equal, * 1 if ptr1 is greater than ptr2 */ -int ucx_ptrcmp(void *ptr1, void *ptr2, void *data); +int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data); /** * Compares two memory areas. @@ -176,7 +203,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(void *ptr1, void *ptr2, void *n); +int ucx_memcmp(const void *ptr1, const void *ptr2, void *n); /** * A printf() like function which writes the output to a stream by @@ -219,10 +246,6 @@ */ 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__) - /** * va_list version of ucx_asprintf(). * @@ -234,8 +257,12 @@ */ sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); +/** Shortcut for ucx_asprintf() with default allocator. */ +#define ucx_sprintf(...) \ + ucx_asprintf(ucx_default_allocator(), __VA_ARGS__) + /** - * A printf() like function which writes the output to an + * A printf() like function which writes the output to a * UcxBuffer. * * @param buffer the buffer the data is written to diff -r 11f3bb408051 -r 62921b370c60 ui/common/types.c --- a/ui/common/types.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ui/common/types.c Sun Jan 21 12:13:09 2018 +0100 @@ -157,6 +157,11 @@ list->data = ucx_list_prepend(list->data, data); } +void ui_list_clear(UiList *list) { + ucx_list_free(list->data); + list->data = NULL; +} + void ui_list_addobsv(UiList *list, ui_callback f, void *data) { list->observers = ui_add_observer(list->observers, f, data); } diff -r 11f3bb408051 -r 62921b370c60 ui/gtk/model.c --- a/ui/gtk/model.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ui/gtk/model.c Sun Jan 21 12:13:09 2018 +0100 @@ -96,7 +96,8 @@ } static void list_model_class_init(GObjectClass *cl, gpointer data) { - //cl->finalize = ...; // TODO + cl->dispose = ui_list_model_dispose; + cl->finalize = ui_list_model_finalize; } @@ -185,6 +186,14 @@ return model; } +void ui_list_model_dispose(GObject *obj) { + +} + +void ui_list_model_finalize(GObject *obj) { + +} + GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) { return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST); diff -r 11f3bb408051 -r 62921b370c60 ui/gtk/model.h --- a/ui/gtk/model.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ui/gtk/model.h Sun Jan 21 12:13:09 2018 +0100 @@ -62,6 +62,9 @@ */ UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info); +void ui_list_model_dispose(GObject *obj); +void ui_list_model_finalize(GObject *obj); + // interface functions diff -r 11f3bb408051 -r 62921b370c60 ui/gtk/tree.c --- a/ui/gtk/tree.c Wed Nov 22 12:59:13 2017 +0100 +++ b/ui/gtk/tree.c Sun Jan 21 12:13:09 2018 +0100 @@ -368,10 +368,19 @@ UiListView *view = list->obj; UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model)); + g_object_unref(G_OBJECT(model)); // TODO: free old model } void ui_listview_destroy(GtkWidget *w, UiListView *v) { + gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); + ui_destroy_boundvar(v->obj->ctx, v->var); + // TODO: destroy model? + free(v); +} + +void ui_combobox_destroy(GtkWidget *w, UiListView *v) { + gtk_combo_box_set_model(GTK_COMBO_BOX(w), NULL); ui_destroy_boundvar(v->obj->ctx, v->var); // TODO: destroy model? free(v); @@ -498,7 +507,7 @@ g_signal_connect( combobox, "destroy", - G_CALLBACK(ui_listview_destroy), + G_CALLBACK(ui_combobox_destroy), uicbox); // bind var diff -r 11f3bb408051 -r 62921b370c60 ui/gtk/tree.h --- a/ui/gtk/tree.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ui/gtk/tree.h Sun Jan 21 12:13:09 2018 +0100 @@ -59,6 +59,7 @@ GtkWidget* ui_get_tree_widget(UIWIDGET widget); void ui_listview_update(UiList *list, int i); +void ui_combobox_destroy(GtkWidget *w, UiListView *v); void ui_listview_destroy(GtkWidget *w, UiListView *v); void ui_listview_activate_event( diff -r 11f3bb408051 -r 62921b370c60 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Wed Nov 22 12:59:13 2017 +0100 +++ b/ui/ui/toolkit.h Sun Jan 21 12:13:09 2018 +0100 @@ -343,6 +343,7 @@ int ui_list_count(UiList *list); void ui_list_append(UiList *list, void *data); void ui_list_prepend(UiList *list, void *data); +void ui_list_clear(UiList *list); void ui_list_addobsv(UiList *list, ui_callback f, void *data); void ui_list_notify(UiList *list);