--- /dev/null
+// ============================================================================
+// list.c
+// ============================================================================
+
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "list.h"
+
+
+/**
+ * List:
+ * @data: holds the element's data, which can be a pointer to any kind
+ * of data, or any integer value using the
+ * [Type Conversion Macros][glib-Type-Conversion-Macros]
+ * @next: contains the link to the next element in the list
+ * @prev: contains the link to the previous element in the list
+ *
+ * The #List struct is used for each element in a doubly-linked list.
+ **/
+
+/**
+ * list_previous:
+ * @list: an element in a #List
+ *
+ * A convenience macro to get the previous element in a #List.
+ * Note that it is considered perfectly acceptable to access
+ * @list->prev directly.
+ *
+ * Returns: the previous element, or %NULL if there are no previous
+ * elements
+ **/
+
+/**
+ * list_next:
+ * @list: an element in a #List
+ *
+ * A convenience macro to get the next element in a #List.
+ * Note that it is considered perfectly acceptable to access
+ * @list->next directly.
+ *
+ * Returns: the next element, or %NULL if there are no more elements
+ **/
+
+/**
+ * list_alloc:
+ *
+ * Allocates space for one #List element. It is called by
+ * list_append(), list_prepend(), list_insert() and
+ * list_insert_sorted() and so is rarely used on its own.
+ *
+ * Returns: a pointer to the newly-allocated #List element
+ **/
+List *
+list_alloc (void)
+{
+ return calloc(1, sizeof(List));
+}
+
+/**
+ * list_free:
+ * @list: the first link of a #List
+ *
+ * Frees all of the memory used by a #List.
+ * The freed elements are returned to the slice allocator.
+ *
+ * If list elements contain dynamically-allocated memory, you should
+ * either use list_free_full() or free them manually first.
+ *
+ * It can be combined with steal_pointer() to ensure the list head pointer
+ * is not left dangling:
+ * |[<!-- language="C" -->
+ * List *list_of_borrowed_things = …; /<!-- -->* (transfer container) *<!-- -->/
+ * list_free (steal_pointer (&list_of_borrowed_things));
+ * ]|
+ */
+void
+list_free (List *list)
+{
+ void *slice = list;
+ size_t next_offset = offsetof(List, next);
+
+ while (slice)
+ {
+ void *current = slice;
+ slice = *(void**) (current + next_offset);
+ free(current);
+ }
+}
+
+/**
+ * list_free_1:
+ * @list: a #List element
+ *
+ * Frees one #List element, but does not update links from the next and
+ * previous elements in the list, so you should not call this function on an
+ * element that is currently part of a list.
+ *
+ * It is usually used after list_remove_link().
+ */
+/**
+ * list_free1:
+ *
+ * Another name for list_free_1().
+ **/
+void
+list_free_1 (List *list)
+{
+ free(list);
+}
+
+/**
+ * list_append:
+ * @list: a pointer to a #List
+ * @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.
+ *
+ * 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 list_prepend() and reverse
+ * the list with list_reverse() when all elements have been added.
+ *
+ * |[<!-- language="C" -->
+ * // Notice that these are initialized to the empty list.
+ * List *strinlist = NULL, *number_list = NULL;
+ *
+ * // This is a list of strings.
+ * strinlist = list_append (strinlist, "first");
+ * strinlist = list_append (strinlist, "second");
+ *
+ * // This is a list of integers.
+ * number_list = list_append (number_list, INT_TO_PTR (27));
+ * number_list = list_append (number_list, INT_TO_PTR (14));
+ * ]|
+ *
+ * Returns: either @list or the new start of the #List if @list was %NULL
+ */
+List *
+list_append (List *list, void *data)
+{
+ List *new_list;
+ List *last;
+
+ new_list = malloc(sizeof(List));
+ new_list->data = data;
+ new_list->next = NULL;
+
+ if (list)
+ {
+ last = list_last(list);
+ last->next = new_list;
+ new_list->prev = last;
+
+ return list;
+ }
+ else
+ {
+ new_list->prev = NULL;
+
+ return new_list;
+ }
+}
+
+/**
+ * list_prepend:
+ * @list: a pointer to a #List, 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.
+ * List *list = NULL;
+ *
+ * list = list_prepend (list, "last");
+ * list = 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 list_insert_before() instead.
+ *
+ * Returns: a pointer to the newly prepended element, which is the new
+ * start of the #List
+ */
+List *
+list_prepend (List *list, void *data)
+{
+ List *new_list;
+
+ new_list = malloc(sizeof(List));
+ 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;
+}
+
+/**
+ * list_insert:
+ * @list: a pointer to a #List, 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 #List
+ */
+List *
+list_insert (List *list, void *data, int position)
+{
+ List *new_list;
+ List *tmp_list;
+
+ if (position < 0)
+ return list_append(list, data);
+ else if (position == 0)
+ return list_prepend(list, data);
+
+ tmp_list = list_nth(list, position);
+ if (!tmp_list)
+ return list_append(list, data);
+
+ new_list = malloc(sizeof(List));
+ 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;
+}
+
+static inline List *
+_list_remove_link (List *list, List *link)
+{
+ if (link == NULL)
+ return list;
+
+ if (link->prev)
+ {
+ if (link->prev->next == link)
+ link->prev->next = link->next;
+ else
+ Warn("corrupted double-linked list detected");
+ }
+
+ if (link->next)
+ {
+ if (link->next->prev == link)
+ link->next->prev = link->prev;
+ else
+ Warn("corrupted double-linked list detected");
+ }
+
+ if (link == list)
+ list = list->next;
+
+ link->next = NULL;
+ link->prev = NULL;
+
+ return list;
+}
+
+/**
+ * list_remove:
+ * @list: a #List, this must point to the top of the list
+ * @data: the data of the element to remove
+ *
+ * Removes an element from a #List.
+ * If two elements contain the same data, only the first is removed.
+ * If none of the elements contain the data, the #List is unchanged.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_remove (List *list, const void *data)
+{
+ List *tmp;
+
+ tmp = list;
+ while (tmp)
+ {
+ if (tmp->data != data)
+ {
+ tmp = tmp->next;
+ }
+ else
+ {
+ list = _list_remove_link (list, tmp);
+ free (tmp);
+
+ break;
+ }
+ }
+
+ return list;
+}
+
+/**
+ * list_remove_all:
+ * @list: a #List, 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
+ * list_remove() which removes only the first node
+ * matching the given data.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_remove_all (List *list, const void *data)
+{
+ List *tmp = list;
+
+ while (tmp)
+ {
+ if (tmp->data != data)
+ {
+ tmp = tmp->next;
+ }
+ else
+ {
+ List *next = tmp->next;
+
+ if (tmp->prev)
+ tmp->prev->next = next;
+ else
+ list = next;
+
+ if (next)
+ next->prev = tmp->prev;
+
+ free (tmp);
+ tmp = next;
+ }
+ }
+
+ return list;
+}
+
+/**
+ * list_remove_link:
+ * @list: a #List, this must point to the top of the list
+ * @llink: an element in the #List
+ *
+ * Removes an element from a #List, 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 list_concat()) or to remove an element in
+ * the list before freeing its data:
+ * |[<!-- language="C" -->
+ * list = list_remove_link (list, llink);
+ * free_some_data_that_may_access_the_list_again (llink->data);
+ * list_free (llink);
+ * ]|
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_remove_link (List *list, List *llink)
+{
+ return _list_remove_link(list, llink);
+}
+
+/**
+ * list_delete_link:
+ * @list: a #List, 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 list_remove_link() which removes the node
+ * without freeing it.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_delete_link (List *list, List *link_)
+{
+ list = _list_remove_link(list, link_);
+ free(link_);
+
+ return list;
+}
+
+/**
+ * list_copy:
+ * @list: a #List, this must point to the top of the list
+ *
+ * Copies a #List.
+ *
+ * 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 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
+ */
+List *
+list_copy (List *list)
+{
+ return list_copy_deep(list, NULL, NULL);
+}
+
+/**
+ * g_list_copy_deep:
+ * @list: a #List, this must point to the top of the list
+ * @func: (scope call): 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 #List.
+ *
+ * In contrast with g_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 #GCopyFunc, takes two arguments, the data to be copied
+ * and a @user_data pointer. On common processor architectures, it's safe to
+ * pass %NULL as @user_data if the copy function takes only one argument. You
+ * may get compiler warnings from this though if compiling with GCC’s
+ * `-Wcast-function-type` warning.
+ *
+ * For instance, if @list holds a list of GObjects, you can do:
+ * |[<!-- language="C" -->
+ * another_list = g_list_copy_deep (list, (GCopyFunc) g_object_ref, NULL);
+ * ]|
+ *
+ * And, to entirely free the new list, you could do:
+ * |[<!-- language="C" -->
+ * g_list_free_full (another_list, g_object_unref);
+ * ]|
+ *
+ * Returns: the start of the new list that holds a full copy of @list,
+ * use g_list_free_full() to free it
+ *
+ * Since: 2.34
+ */
+List *
+list_copy_deep (List *list, list_copy_fn func, void *user_data)
+{
+ List *new_list = NULL;
+
+ if (list)
+ {
+ List *last;
+
+ new_list = malloc(sizeof(List));
+
+ 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 = malloc(sizeof(List));
+ 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;
+}
+
+/**
+ * list_reverse:
+ * @list: a #List, this must point to the top of the list
+ *
+ * Reverses a #List.
+ * It simply switches the next and prev pointers of each element.
+ *
+ * Returns: the start of the reversed #List
+ */
+List *
+list_reverse (List *list)
+{
+ List *last;
+
+ last = NULL;
+
+ while (list)
+ {
+ last = list;
+ list = last->next;
+ last->next = last->prev;
+ last->prev = list;
+ }
+
+ return last;
+}
+
+/**
+ * list_nth:
+ * @list: a #List, 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 #List.
+ *
+ * This iterates over the list until it reaches the @n-th position. If you
+ * intend to iterate over every element, it is better to use a for-loop as
+ * described in the #List introduction.
+ *
+ * Returns: the element, or %NULL if the position is off
+ * the end of the #List
+ */
+List *
+list_nth (List *list, unsigned int n)
+{
+ while ((n-- > 0) && list)
+ list = list->next;
+
+ return list;
+}
+
+/**
+ * list_nth_prev:
+ * @list: a #List
+ * @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 #List
+ */
+List *
+list_nth_prev (List *list, unsigned int n)
+{
+ while ((n-- > 0) && list)
+ list = list->prev;
+
+ return list;
+}
+
+/**
+ * list_nth_data:
+ * @list: a #List, 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.
+ *
+ * This iterates over the list until it reaches the @n-th position. If you
+ * intend to iterate over every element, it is better to use a for-loop as
+ * described in the #List introduction.
+ *
+ * Returns: the element's data, or %NULL if the position
+ * is off the end of the #List
+ */
+void *
+list_nth_data (List *list, unsigned int n)
+{
+ while ((n-- > 0) && list)
+ list = list->next;
+
+ return list ? list->data : NULL;
+}
+
+/**
+ * list_position:
+ * @list: a #List, this must point to the top of the list
+ * @llink: an element in the #List
+ *
+ * Gets the position of the given element
+ * in the #List (starting from 0).
+ *
+ * Returns: the position of the element in the #List,
+ * or -1 if the element is not found
+ */
+int
+list_position (List *list, List *llink)
+{
+ int i;
+
+ i = 0;
+ while (list)
+ {
+ if (list == llink)
+ return i;
+
+ i++;
+ list = list->next;
+ }
+
+ return -1;
+}
+
+/**
+ * list_index:
+ * @list: a #List, 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
+list_index (List *list, const void *data)
+{
+ int i;
+
+ i = 0;
+ while (list)
+ {
+ if (list->data == data)
+ return i;
+
+ i++;
+ list = list->next;
+ }
+
+ return -1;
+}
+
+/**
+ * list_last:
+ * @list: any #List element
+ *
+ * Gets the last element in a #List.
+ *
+ * Returns: the last element in the #List,
+ * or %NULL if the #List has no elements
+ */
+List *
+list_last (List *list)
+{
+ if (list)
+ {
+ while (list->next)
+ list = list->next;
+ }
+
+ return list;
+}
+
+/**
+ * list_first:
+ * @list: any #List element
+ *
+ * Gets the first element in a #List.
+ *
+ * Returns: the first element in the #List,
+ * or %NULL if the #List has no elements
+ */
+List *
+list_first (List *list)
+{
+ if (list)
+ {
+ while (list->prev)
+ list = list->prev;
+ }
+
+ return list;
+}
+
+/**
+ * list_length:
+ * @list: a #List, this must point to the top of the list
+ *
+ * Gets the number of elements in a #List.
+ *
+ * This function iterates over the whole list to count its elements.
+ * Use a #GQueue instead of a List if you regularly need the number
+ * of items. To check whether the list is non-empty, it is faster to check
+ * @list against %NULL.
+ *
+ * Returns: the number of elements in the #List
+ */
+unsigned int
+list_length (List *list)
+{
+ unsigned int length;
+
+ length = 0;
+ while (list)
+ {
+ length++;
+ list = list->next;
+ }
+
+ return length;
+}
+
+/**
+ * list_foreach:
+ * @list: a #List, this must point to the top of the list
+ * @func: (scope call): 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 #List.
+ *
+ * It is safe for @func to remove the element from @list, but it must
+ * not modify any part of the list after that element.
+ */
+/**
+ * list_fn:
+ * @data: the element's data
+ * @user_data: user data passed to list_foreach() or slist_foreach()
+ *
+ * Specifies the type of functions passed to list_foreach() and
+ * slist_foreach().
+ */
+void
+list_foreach (List *list, list_fn func, void *user_data)
+{
+ while (list)
+ {
+ List *next = list->next;
+
+ (*func) (list->data, user_data);
+ list = next;
+ }
+}