From 4d28f495c8c42e94d3040608131f0cdcbc4f6b8d Mon Sep 17 00:00:00 2001
From: Aleksandr Lysikov <lysikov@inbox.ru>
Date: Wed, 27 Mar 2019 22:47:52 +0500
Subject: [PATCH] added DapList functions

---
 core/dap_list.c | 1005 +++++++++++++++++++++++++++++++++++++++++++++++
 core/dap_list.h |   62 +++
 2 files changed, 1067 insertions(+)
 create mode 100755 core/dap_list.c
 create mode 100755 core/dap_list.h

diff --git a/core/dap_list.c b/core/dap_list.c
new file mode 100755
index 0000000..e47aadf
--- /dev/null
+++ b/core/dap_list.c
@@ -0,0 +1,1005 @@
+/*
+ * Doubly-Linked Lists — linked lists that can be iterated over in both directions
+ */
+
+#include <stddef.h>
+
+#include "dap_common.h"
+#include "dap_strfuncs.h"
+#include "dap_list.h"
+
+
+#define LOG_TAG "dap_list"
+
+/**
+ * dap_list_alloc:
+ * Returns: a pointer to the newly-allocated DapList element
+ **/
+DapList *dap_list_alloc(void)
+{
+    DapList *list = DAP_NEW(DapList);
+    return list;
+}
+
+DapList *dap_list_alloc0(void)
+{
+    DapList *list = DAP_NEW_Z(DapList);
+    return list;
+}
+
+/**
+ * dap_list_free:
+ * Frees all of the memory used by a DapList.
+ * The freed elements are returned to the slice allocator.
+ * If list elements contain dynamically-allocated memory, you should
+ * either use dap_list_free_full() or free them manually first.
+ */
+void dap_list_free(DapList *list)
+{
+    while(list)
+    {
+        DapList *next = list->next;
+        DAP_DELETE(list);
+        list = next;
+    }
+}
+
+/**
+ * dap_list_free_1:
+ *
+ * Frees one DapList element.
+ * It is usually used after dap_list_remove_link().
+ */
+void dap_list_free1(DapList *list)
+{
+    DAP_DELETE(list);
+}
+
+/**
+ * dap_list_free_full:
+ * @list: a pointer to a DapList
+ * @free_func: the function to be called to free each element's data
+ *
+ * Convenience method, which frees all the memory used by a DapList,
+ * and calls @free_func on every element's data.
+ */
+void dap_list_free_full(DapList *list, DapDestroyNotify free_func)
+{
+    dap_list_foreach(list, (DapFunc) free_func, NULL);
+    dap_list_free(list);
+}
+
+/**
+ * dap_list_append:
+ * @list: a pointer to a DapList
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the end of the list.
+ *
+ * Note that the return value is the new start of the list,
+ * if @list was empty; make sure you store the new value.
+ *
+ * dap_list_append() has to traverse the entire list to find the end,
+ * which is inefficient when adding multiple elements. A common idiom
+ * to avoid the inefficiency is to use dap_list_prepend() and reverse
+ * the list with dap_list_reverse() when all elements have been added.
+ *
+ * |[<!-- language="C" -->
+ * // Notice that these are initialized to the empty list.
+ * DapList *string_list = NULL, *number_list = NULL;
+ *
+ * // This is a list of strings.
+ * string_list = dap_list_append (string_list, "first");
+ * string_list = dap_list_append (string_list, "second");
+ * 
+ * // This is a list of integers.
+ * number_list = dap_list_append (number_list, INT_TO_POINTER (27));
+ * number_list = dap_list_append (number_list, INT_TO_POINTER (14));
+ * ]|
+ *
+ * Returns: either @list or the new start of the DapList if @list was %NULL
+ */
+DapList * dap_list_append(DapList *list, void* data)
+{
+    DapList *new_list;
+    DapList *last;
+
+    new_list = dap_list_alloc();
+    new_list->data = data;
+    new_list->next = NULL;
+
+    if(list)
+    {
+        last = dap_list_last(list);
+        /* assert (last != NULL); */
+        last->next = new_list;
+        new_list->prev = last;
+
+        return list;
+    }
+    else
+    {
+        new_list->prev = NULL;
+        return new_list;
+    }
+}
+
+/**
+ * dap_list_prepend:
+ * @list: a pointer to a DapList, this must point to the top of the list
+ * @data: the data for the new element
+ *
+ * Prepends a new element on to the start of the list.
+ *
+ * Note that the return value is the new start of the list,
+ * which will have changed, so make sure you store the new value. 
+ *
+ * |[<!-- language="C" -->
+ * // Notice that it is initialized to the empty list.
+ * DapList *list = NULL;
+ *
+ * list = dap_list_prepend (list, "last");
+ * list = dap_list_prepend (list, "first");
+ * ]|
+ *
+ * Do not use this function to prepend a new element to a different
+ * element than the start of the list. Use dap_list_insert_before() instead.
+ *
+ * Returns: a pointer to the newly prepended element, which is the new 
+ *     start of the DapList
+ */
+DapList *dap_list_prepend(DapList *list, void* data)
+{
+    DapList *new_list;
+
+    new_list = dap_list_alloc();
+    new_list->data = data;
+    new_list->next = list;
+
+    if(list)
+    {
+        new_list->prev = list->prev;
+        if(list->prev)
+            list->prev->next = new_list;
+        list->prev = new_list;
+    }
+    else
+        new_list->prev = NULL;
+
+    return new_list;
+}
+
+/**
+ * dap_list_insert:
+ * @list: a pointer to a DapList, this must point to the top of the list
+ * @data: the data for the new element
+ * @position: the position to insert the element. If this is 
+ *     negative, or is larger than the number of elements in the 
+ *     list, the new element is added on to the end of the list.
+ * 
+ * Inserts a new element into the list at the given position.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_insert(DapList *list, void* data, int position)
+{
+    DapList *new_list;
+    DapList *tmp_list;
+
+    if(position < 0)
+        return dap_list_append(list, data);
+    else if(position == 0)
+        return dap_list_prepend(list, data);
+
+    tmp_list = dap_list_nth(list, position);
+    if(!tmp_list)
+        return dap_list_append(list, data);
+
+    new_list = dap_list_alloc();
+    new_list->data = data;
+    new_list->prev = tmp_list->prev;
+    tmp_list->prev->next = new_list;
+    new_list->next = tmp_list;
+    tmp_list->prev = new_list;
+
+    return list;
+}
+
+/**
+ * dap_list_insert_before:
+ * @list: a pointer to a DapList, this must point to the top of the list
+ * @sibling: the list element before which the new element 
+ *     is inserted or %NULL to insert at the end of the list
+ * @data: the data for the new element
+ *
+ * Inserts a new element into the list before the given position.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_insert_before(DapList *list, DapList *sibling, void* data)
+{
+    if(!list)
+    {
+        list = dap_list_alloc();
+        list->data = data;
+        dap_return_val_if_fail(sibling == NULL, list);
+        return list;
+    }
+    else if(sibling)
+    {
+        DapList *node;
+
+        node = dap_list_alloc();
+        node->data = data;
+        node->prev = sibling->prev;
+        node->next = sibling;
+        sibling->prev = node;
+        if(node->prev)
+        {
+            node->prev->next = node;
+            return list;
+        }
+        else
+        {
+            dap_return_val_if_fail(sibling == list, node);
+            return node;
+        }
+    }
+    else
+    {
+        DapList *last;
+
+        last = list;
+        while(last->next)
+            last = last->next;
+
+        last->next = dap_list_alloc();
+        last->next->data = data;
+        last->next->prev = last;
+        last->next->next = NULL;
+
+        return list;
+    }
+}
+
+/**
+ * dap_list_concat:
+ * @list1: a DapList, this must point to the top of the list
+ * @list2: the DapList to add to the end of the first DapList,
+ *     this must point  to the top of the list
+ *
+ * Adds the second DapList onto the end of the first DapList.
+ * Note that the elements of the second DapList are not copied.
+ * They are used directly.
+ *
+ * This function is for example used to move an element in the list.
+ * The following example moves an element to the top of the list:
+ * |[<!-- language="C" -->
+ * list = dap_list_remove_link (list, llink);
+ * list = dap_list_concat (llink, list);
+ * ]|
+ *
+ * Returns: the start of the new DapList, which equals @list1 if not %NULL
+ */
+DapList *dap_list_concat(DapList *list1, DapList *list2)
+{
+    DapList *tmp_list;
+
+    if(list2)
+    {
+        tmp_list = dap_list_last(list1);
+        if(tmp_list)
+            tmp_list->next = list2;
+        else
+            list1 = list2;
+        list2->prev = tmp_list;
+    }
+
+    return list1;
+}
+
+static inline DapList * _dap_list_remove_link(DapList *list, DapList *link)
+{
+    if(link == NULL)
+        return list;
+
+    if(link->prev)
+    {
+        if(link->prev->next == link)
+            link->prev->next = link->next;
+        else
+            log_it(L_ERROR, "corrupted double-linked list detected");
+    }
+    if(link->next)
+    {
+        if(link->next->prev == link)
+            link->next->prev = link->prev;
+        else
+            log_it(L_ERROR, "corrupted double-linked list detected");
+    }
+
+    if(link == list)
+        list = list->next;
+
+    link->next = NULL;
+    link->prev = NULL;
+
+    return list;
+}
+
+/**
+ * dap_list_remove:
+ * @list: a DapList, this must point to the top of the list
+ * @data: the data of the element to remove
+ *
+ * Removes an element from a DapList.
+ * If two elements contain the same data, only the first is removed.
+ * If none of the elements contain the data, the DapList is unchanged.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_remove(DapList *list, const void * data)
+{
+    DapList *tmp;
+
+    tmp = list;
+    while(tmp)
+    {
+        if(tmp->data != data)
+            tmp = tmp->next;
+        else
+        {
+            list = _dap_list_remove_link(list, tmp);
+            dap_list_free1(tmp);
+
+            break;
+        }
+    }
+    return list;
+}
+
+/**
+ * dap_list_remove_all:
+ * @list: a DapList, this must point to the top of the list
+ * @data: data to remove
+ *
+ * Removes all list nodes with data equal to @data.
+ * Returns the new head of the list. Contrast with
+ * dap_list_remove() which removes only the first node
+ * matching the given data.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_remove_all(DapList *list, const void * data)
+{
+    DapList *tmp = list;
+
+    while(tmp)
+    {
+        if(tmp->data != data)
+            tmp = tmp->next;
+        else
+        {
+            DapList *next = tmp->next;
+
+            if(tmp->prev)
+                tmp->prev->next = next;
+            else
+                list = next;
+            if(next)
+                next->prev = tmp->prev;
+
+            dap_list_free1(tmp);
+            tmp = next;
+        }
+    }
+    return list;
+}
+
+/**
+ * dap_list_remove_link:
+ * @list: a DapList, this must point to the top of the list
+ * @llink: an element in the DapList
+ *
+ * Removes an element from a DapList, without freeing the element.
+ * The removed element's prev and next links are set to %NULL, so 
+ * that it becomes a self-contained list with one element.
+ *
+ * This function is for example used to move an element in the list
+ * (see the example for dap_list_concat()) or to remove an element in
+ * the list before freeing its data:
+ * |[<!-- language="C" --> 
+ * list = dap_list_remove_link (list, llink);
+ * free_some_data_that_may_access_the_list_again (llink->data);
+ * dap_list_free (llink);
+ * ]|
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_remove_link(DapList *list, DapList *llink)
+{
+    return _dap_list_remove_link(list, llink);
+}
+
+/**
+ * dap_list_delete_link:
+ * @list: a DapList, this must point to the top of the list
+ * @link_: node to delete from @list
+ *
+ * Removes the node link_ from the list and frees it. 
+ * Compare this to dap_list_remove_link() which removes the node
+ * without freeing it.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_delete_link(DapList *list, DapList *link_)
+{
+    list = _dap_list_remove_link(list, link_);
+    dap_list_free1(link_);
+
+    return list;
+}
+
+/**
+ * dap_list_copy:
+ * @list: a DapList, this must point to the top of the list
+ *
+ * Copies a DapList.
+ *
+ * Note that this is a "shallow" copy. If the list elements 
+ * consist of pointers to data, the pointers are copied but 
+ * the actual data is not. See dap_list_copy_deep() if you need
+ * to copy the data as well.
+ *
+ * Returns: the start of the new list that holds the same data as @list
+ */
+DapList *dap_list_copy(DapList *list)
+{
+    return dap_list_copy_deep(list, NULL, NULL);
+}
+
+/**
+ * dap_list_copy_deep:
+ * @list: a DapList, this must point to the top of the list
+ * @func: a copy function used to copy every element in the list
+ * @user_data: user data passed to the copy function @func, or %NULL
+ *
+ * Makes a full (deep) copy of a DapList.
+ *
+ * In contrast with dap_list_copy(), this function uses @func to make
+ * a copy of each list element, in addition to copying the list
+ * container itself.
+ *
+ * @func, as a #DapCopyFunc, takes two arguments, the data to be copied
+ * and a @user_data pointer. It's safe to pass %NULL as user_data,
+ * if the copy function takes only one argument.
+ *
+ * For instance,
+ * |[<!-- language="C" -->   
+ * another_list = dap_list_copy_deep (list, (DapCopyFunc) dap_object_ref, NULL);
+ * ]|
+ *
+ * And, to entirely free the new list, you could do:
+ * |[<!-- language="C" --> 
+ * dap_list_free_full (another_list, dap_object_unref);
+ * ]|
+ *
+ * Returns: the start of the new list that holds a full copy of @list, 
+ *     use dap_list_free_full() to free it
+ */
+DapList *dap_list_copy_deep(DapList *list, DapCopyFunc func, void* user_data)
+{
+    DapList *new_list = NULL;
+
+    if(list)
+    {
+        DapList *last;
+
+        new_list = dap_list_alloc();
+        if(func)
+            new_list->data = func(list->data, user_data);
+        else
+            new_list->data = list->data;
+        new_list->prev = NULL;
+        last = new_list;
+        list = list->next;
+        while(list)
+        {
+            last->next = dap_list_alloc();
+            last->next->prev = last;
+            last = last->next;
+            if(func)
+                last->data = func(list->data, user_data);
+            else
+                last->data = list->data;
+            list = list->next;
+        }
+        last->next = NULL;
+    }
+
+    return new_list;
+}
+
+/**
+ * dap_list_reverse:
+ * @list: a DapList, this must point to the top of the list
+ *
+ * Reverses a DapList.
+ * It simply switches the next and prev pointers of each element.
+ *
+ * Returns: the start of the reversed DapList
+ */
+DapList * dap_list_reverse(DapList *list)
+{
+    DapList *last;
+
+    last = NULL;
+    while(list)
+    {
+        last = list;
+        list = last->next;
+        last->next = last->prev;
+        last->prev = list;
+    }
+
+    return last;
+}
+
+/**
+ * dap_list_nth:
+ * @list: a DapList, this must point to the top of the list
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element at the given position in a DapList.
+ *
+ * Returns: the element, or %NULL if the position is off 
+ *     the end of the DapList
+ */
+DapList *dap_list_nth(DapList *list, unsigned int n)
+{
+    while((n-- > 0) && list)
+        list = list->next;
+
+    return list;
+}
+
+/**
+ * dap_list_nth_prev:
+ * @list: a DapList
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element @n places before @list.
+ *
+ * Returns: the element, or %NULL if the position is 
+ *     off the end of the DapList
+ */
+DapList *dap_list_nth_prev(DapList *list, unsigned int n)
+{
+    while((n-- > 0) && list)
+        list = list->prev;
+
+    return list;
+}
+
+/**
+ * dap_list_nth_data:
+ * @list: a DapList, this must point to the top of the list
+ * @n: the position of the element
+ *
+ * Gets the data of the element at the given position.
+ *
+ * Returns: the element's data, or %NULL if the position 
+ *     is off the end of the DapList
+ */
+void* dap_list_nth_data(DapList *list, unsigned int n)
+{
+    while((n-- > 0) && list)
+        list = list->next;
+
+    return list ? list->data : NULL ;
+}
+
+/**
+ * dap_list_find:
+ * @list: a DapList, this must point to the top of the list
+ * @data: the element data to find
+ *
+ * Finds the element in a DapList which contains the given data.
+ *
+ * Returns: the found DapList element, or %NULL if it is not found
+ */
+DapList *dap_list_find(DapList *list, const void * data)
+{
+    while(list)
+    {
+        if(list->data == data)
+            break;
+        list = list->next;
+    }
+
+    return list;
+}
+
+/**
+ * dap_list_find_custom:
+ * @list: a DapList, this must point to the top of the list
+ * @data: user data passed to the function
+ * @func: the function to call for each element. 
+ *     It should return 0 when the desired element is found
+ *
+ * Finds an element in a DapList, using a supplied function to
+ * find the desired element. It iterates over the list, calling 
+ * the given function which should return 0 when the desired 
+ * element is found. The function takes two const pointer arguments,
+ * the DapList element's data as the first argument and the
+ * given user data.
+ *
+ * Returns: the found DapList element, or %NULL if it is not found
+ */
+DapList *dap_list_find_custom(DapList *list, const void * data, DapCompareFunc func)
+{
+    dap_return_val_if_fail(func != NULL, list);
+
+    while(list)
+    {
+        if(!func(list->data, data))
+            return list;
+        list = list->next;
+    }
+
+    return NULL ;
+}
+
+/**
+ * dap_list_position:
+ * @list: a DapList, this must point to the top of the list
+ * @llink: an element in the DapList
+ *
+ * Gets the position of the given element 
+ * in the DapList (starting from 0).
+ *
+ * Returns: the position of the element in the DapList,
+ *     or -1 if the element is not found
+ */
+int dap_list_position(DapList *list, DapList *llink)
+{
+    int i;
+
+    i = 0;
+    while(list)
+    {
+        if(list == llink)
+            return i;
+        i++;
+        list = list->next;
+    }
+
+    return -1;
+}
+
+/**
+ * dap_list_index:
+ * @list: a DapList, this must point to the top of the list
+ * @data: the data to find
+ *
+ * Gets the position of the element containing 
+ * the given data (starting from 0).
+ *
+ * Returns: the index of the element containing the data, 
+ *     or -1 if the data is not found
+ */
+int dap_list_index(DapList *list, const void * data)
+{
+    int i;
+
+    i = 0;
+    while(list)
+    {
+        if(list->data == data)
+            return i;
+        i++;
+        list = list->next;
+    }
+
+    return -1;
+}
+
+/**
+ * dap_list_last:
+ * @list: any DapList element
+ *
+ * Gets the last element in a DapList.
+ *
+ * Returns: the last element in the DapList,
+ *     or %NULL if the DapList has no elements
+ */
+DapList * dap_list_last(DapList *list)
+{
+    if(list)
+    {
+        while(list->next)
+            list = list->next;
+    }
+
+    return list;
+}
+
+/**
+ * dap_list_first:
+ * @list: any DapList element
+ *
+ * Gets the first element in a DapList.
+ *
+ * Returns: the first element in the DapList,
+ *     or %NULL if the DapList has no elements
+ */
+DapList *dap_list_first(DapList *list)
+{
+    if(list)
+    {
+        while(list->prev)
+            list = list->prev;
+    }
+
+    return list;
+}
+
+/**
+ * dap_list_length:
+ * @list: a DapList, this must point to the top of the list
+ *
+ * Gets the number of elements in a DapList.
+ *
+ * This function iterates over the whole list to count its elements.
+ *
+ * Returns: the number of elements in the DapList
+ */
+unsigned int dap_list_length(DapList *list)
+{
+    unsigned int length;
+
+    length = 0;
+    while(list)
+    {
+        length++;
+        list = list->next;
+    }
+
+    return length;
+}
+
+/**
+ * dap_list_foreach:
+ * @list: a DapList, this must point to the top of the list
+ * @func: the function to call with each element's data
+ * @user_data: user data to pass to the function
+ *
+ * Calls a function for each element of a DapList.
+ */
+void dap_list_foreach(DapList *list, DapFunc func, void* user_data)
+{
+    while(list)
+    {
+        DapList *next = list->next;
+        (*func)(list->data, user_data);
+        list = next;
+    }
+}
+
+static DapList* dap_list_insert_sorted_real(DapList *list, void* data, DapFunc func, void* user_data)
+{
+    DapList *tmp_list = list;
+    DapList *new_list;
+    int cmp;
+
+    dap_return_val_if_fail(func != NULL, list);
+
+    if(!list)
+    {
+        new_list = dap_list_alloc0();
+        new_list->data = data;
+        return new_list;
+    }
+
+    cmp = ((DapCompareDataFunc) func)(data, tmp_list->data, user_data);
+
+    while((tmp_list->next) && (cmp > 0))
+    {
+        tmp_list = tmp_list->next;
+
+        cmp = ((DapCompareDataFunc) func)(data, tmp_list->data, user_data);
+    }
+
+    new_list = dap_list_alloc0();
+    new_list->data = data;
+
+    if((!tmp_list->next) && (cmp > 0))
+            {
+        tmp_list->next = new_list;
+        new_list->prev = tmp_list;
+        return list;
+    }
+
+    if(tmp_list->prev)
+    {
+        tmp_list->prev->next = new_list;
+        new_list->prev = tmp_list->prev;
+    }
+    new_list->next = tmp_list;
+    tmp_list->prev = new_list;
+
+    if(tmp_list == list)
+        return new_list;
+    else
+        return list;
+}
+
+/**
+ * dap_list_insert_sorted:
+ * @list: a pointer to a DapList, this must point to the top of the
+ *     already sorted list
+ * @data: the data for the new element
+ * @func: the function to compare elements in the list. It should
+ *     return a number > 0 if the first parameter comes after the
+ *     second parameter in the sort order.
+ *
+ * Inserts a new element into the list, using the given comparison
+ * function to determine its position.
+ *
+ * If you are adding many new elements to a list, and the number of
+ * new elements is much larger than the length of the list, use
+ * dap_list_prepend() to add the new items and sort the list afterwards
+ * with dap_list_sort().
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList *dap_list_insert_sorted(DapList *list, void* data, DapCompareFunc func)
+{
+    return dap_list_insert_sorted_real(list, data, (DapFunc) func, NULL);
+}
+
+/**
+ * dap_list_insert_sorted_with_data:
+ * @list: a pointer to a DapList, this must point to the top of the
+ *     already sorted list
+ * @data: the data for the new element
+ * @func: the function to compare elements in the list. It should
+ *     return a number > 0 if the first parameter  comes after the
+ *     second parameter in the sort order.
+ * @user_data: user data to pass to comparison function
+ *
+ * Inserts a new element into the list, using the given comparison 
+ * function to determine its position.
+ *
+ * If you are adding many new elements to a list, and the number of
+ * new elements is much larger than the length of the list, use
+ * dap_list_prepend() to add the new items and sort the list afterwards
+ * with dap_list_sort().
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+DapList * dap_list_insert_sorted_with_data(DapList *list, void* data, DapCompareDataFunc func, void* user_data)
+{
+    return dap_list_insert_sorted_real(list, data, (DapFunc) func, user_data);
+}
+
+static DapList *dap_list_sort_merge(DapList *l1, DapList *l2, DapFunc compare_func, void* user_data)
+{
+    DapList list, *l, *lprev;
+    int cmp;
+
+    l = &list;
+    lprev = NULL;
+
+    while(l1 && l2)
+    {
+        cmp = ((DapCompareDataFunc) compare_func)(l1->data, l2->data, user_data);
+
+        if(cmp <= 0)
+                {
+            l->next = l1;
+            l1 = l1->next;
+        }
+        else
+        {
+            l->next = l2;
+            l2 = l2->next;
+        }
+        l = l->next;
+        l->prev = lprev;
+        lprev = l;
+    }
+    l->next = l1 ? l1 : l2;
+    l->next->prev = l;
+
+    return list.next;
+}
+
+static DapList *dap_list_sort_real(DapList *list, DapFunc compare_func, void* user_data)
+{
+    DapList *l1, *l2;
+
+    if(!list)
+        return NULL ;
+    if(!list->next)
+        return list;
+
+    l1 = list;
+    l2 = list->next;
+
+    while((l2 = l2->next) != NULL )
+    {
+        if((l2 = l2->next) == NULL)
+            break;
+        l1 = l1->next;
+    }
+    l2 = l1->next;
+    l1->next = NULL;
+
+    return dap_list_sort_merge(dap_list_sort_real(list, compare_func, user_data),
+            dap_list_sort_real(l2, compare_func, user_data),
+            compare_func,
+            user_data);
+}
+
+/**
+ * dap_list_sort:
+ * @list: a DapList, this must point to the top of the list
+ * @compare_func: the comparison function used to sort the DapList.
+ *     This function is passed the data from 2 elements of the DapList
+ *     and should return 0 if they are equal, a negative value if the 
+ *     first element comes before the second, or a positive value if 
+ *     the first element comes after the second.
+ *
+ * Sorts a DapList using the given comparison function. The algorithm
+ * used is a stable sort.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+/**
+ * DapCompareFunc:
+ * @a: a value
+ * @b: a value to compare with
+ *
+ * Specifies the type of a comparison function used to compare two
+ * values.  The function should return a negative integer if the first
+ * value comes before the second, 0 if they are equal, or a positive
+ * integer if the first value comes after the second.
+ *
+ * Returns: negative value if @a < @b; zero if @a = @b; positive
+ *          value if @a > @b
+ */
+DapList *dap_list_sort(DapList *list, DapCompareFunc compare_func)
+{
+    return dap_list_sort_real(list, (DapFunc) compare_func, NULL);
+}
+
+/**
+ * dap_list_sort_with_data:
+ * @list: a DapList, this must point to the top of the list
+ * @compare_func: comparison function
+ * @user_data: user data to pass to comparison function
+ *
+ * Like dap_list_sort(), but the comparison function accepts
+ * a user data argument.
+ *
+ * Returns: the (possibly changed) start of the DapList
+ */
+/**
+ * DapCompareFunc:
+ * @a: a value
+ * @b: a value to compare with
+ * @user_data: user data
+ *
+ * Specifies the type of a comparison function used to compare two
+ * values.  The function should return a negative integer if the first
+ * value comes before the second, 0 if they are equal, or a positive
+ * integer if the first value comes after the second.
+ *
+ * Returns: negative value if @a < @b; zero if @a = @b; positive
+ *          value if @a > @b
+ */
+DapList *dap_list_sort_with_data(DapList *list, DapCompareDataFunc compare_func, void* user_data)
+{
+    return dap_list_sort_real(list, (DapFunc) compare_func, user_data);
+}
diff --git a/core/dap_list.h b/core/dap_list.h
new file mode 100755
index 0000000..08445a2
--- /dev/null
+++ b/core/dap_list.h
@@ -0,0 +1,62 @@
+/*
+ * Doubly-Linked Lists — linked lists that can be iterated over in both directions
+ */
+
+#ifndef __DAP_LIST_H__
+#define __DAP_LIST_H__
+
+typedef void (*DapDestroyNotify)(void* data);
+typedef void (*DapFunc)(void* data, void* user_data);
+typedef void* (*DapCopyFunc)(const void * src, void* data);
+typedef int (*DapCompareFunc)(const void * a, const void * b);
+typedef int (*DapCompareDataFunc)(const void * a, const void * b, void* user_data);
+
+typedef struct _DapList DapList;
+
+struct _DapList
+{
+    void* data;
+    DapList *next;
+    DapList *prev;
+};
+
+/* Doubly linked lists
+ */
+DapList* dap_list_alloc(void);
+void dap_list_free(DapList *list);
+void dap_list_free1(DapList *list);
+void dap_list_free_full(DapList *list, DapDestroyNotify free_func);
+DapList* dap_list_append(DapList *list, void* data);
+DapList* dap_list_prepend(DapList *list, void* data);
+DapList* dap_list_insert(DapList *list, void* data, int position);
+DapList* dap_list_insert_sorted(DapList *list, void* data, DapCompareFunc func);
+DapList* dap_list_insert_sorted_with_data(DapList *list, void* data, DapCompareDataFunc func, void* user_data);
+DapList* dap_list_insert_before(DapList *list, DapList *sibling, void* data);
+DapList* dap_list_concat(DapList *list1, DapList *list2);
+DapList* dap_list_remove(DapList *list, const void * data);
+DapList* dap_list_remove_all(DapList *list, const void * data);
+DapList* dap_list_remove_link(DapList *list, DapList *llink);
+DapList* dap_list_delete_link(DapList *list, DapList *link_);
+DapList* dap_list_reverse(DapList *list);
+DapList* dap_list_copy(DapList *list);
+
+DapList* dap_list_copy_deep(DapList *list, DapCopyFunc func, void* user_data);
+
+DapList* dap_list_nth(DapList *list, unsigned int n);
+DapList* dap_list_nth_prev(DapList *list, unsigned int n);
+DapList* dap_list_find(DapList *list, const void * data);
+DapList* dap_list_find_custom(DapList *list, const void * data, DapCompareFunc func);
+int dap_list_position(DapList *list, DapList *llink);
+int dap_list_index(DapList *list, const void * data);
+DapList* dap_list_last(DapList *list);
+DapList* dap_list_first(DapList *list);
+unsigned int dap_list_length(DapList *list);
+void dap_list_foreach(DapList *list, DapFunc func, void* user_data);
+DapList* dap_list_sort(DapList *list, DapCompareFunc compare_func);
+DapList* dap_list_sort_with_data(DapList *list, DapCompareDataFunc compare_func, void* user_data);
+void* dap_list_nth_data(DapList *list, unsigned int n);
+
+#define dap_list_previous(list)	        ((list) ? (((DapList *)(list))->prev) : NULL)
+#define dap_list_next(list)	        ((list) ? (((DapList *)(list))->next) : NULL)
+
+#endif /* __DAP_LIST_H__ */
-- 
GitLab