2 * Copyright (C) 2000-2007 Carsten Haitzler and various contributors (see AUTHORS)
4 * Copyright (C) Nathan Ingersoll (author)
5 * Copyright (C) Ibukun Olumuyiwa (ewd -> ecore)
6 * Copyright (C) Dan Sinclair (various cleanups)
7 * Copyright (C) Kim Woelders (e16 port/additions)
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to
11 * deal in the Software without restriction, including without limitation the
12 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 * sell copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies of the Software, its documentation and marketing & publicity
18 * materials, and acknowledgment shall be given in the documentation, materials
19 * and software packages that this Software was used.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 * Most of this was snatched from e17/libs/ecore/src/lib/ecore/ecore_list.c
30 * revision 1.21, and associated header files.
31 * The pertinent AUTHORS list is e17/libs/ecore/AUTHORS.
35 #include "e16-ecore_list.h"
46 struct _ecore_list_node {
48 struct _ecore_list_node *next;
52 Ecore_List_Node *first; /* The first node in the list */
53 Ecore_List_Node *last; /* The last node in the list */
54 Ecore_List_Node *current; /* The current node in the list */
56 Ecore_Free_Cb free_func; /* The callback to free data in nodes */
58 int nodes; /* The number of nodes in the list */
59 int index; /* The position from the front of the
60 * list of current node */
63 /* convenience macros for checking pointer parameters for non-NULL */
64 #define ecore_print_warning(txt, s)
66 #undef CHECK_PARAM_POINTER
67 #define CHECK_PARAM_POINTER(sparam, param) \
69 ecore_print_warning(__FUNCTION__, sparam); \
73 #define CHECK_PARAM_POINTER_RETURN(sparam, param, ret) \
75 ecore_print_warning(__FUNCTION__, sparam); \
79 /* Return information about the list */
80 static void *_ecore_list_current(Ecore_List * list);
82 /* Adding functions */
83 static int _ecore_list_insert(Ecore_List * list,
84 Ecore_List_Node * node);
85 static int _ecore_list_append_0(Ecore_List * list,
86 Ecore_List_Node * node);
87 static int _ecore_list_prepend_0(Ecore_List * list,
88 Ecore_List_Node * node);
90 /* Remove functions */
91 static void *_ecore_list_remove_0(Ecore_List * list);
92 static void *_ecore_list_first_remove(Ecore_List * list);
93 static void *_ecore_list_last_remove(Ecore_List * list);
95 /* Basic traversal functions */
96 static void *_ecore_list_next(Ecore_List * list);
97 static void *_ecore_list_last_goto(Ecore_List * list);
98 static void *_ecore_list_first_goto(Ecore_List * list);
99 static void *_ecore_list_goto(Ecore_List * list, const void *data);
100 static void *_ecore_list_index_goto(Ecore_List * list, int indx);
102 /* Iterative function */
103 static int _ecore_list_for_each(Ecore_List * list,
104 Ecore_For_Each function,
106 static void *_ecore_list_find(Ecore_List * list,
107 Ecore_Compare_Cb function,
108 const void *user_data);
111 * @defgroup Ecore_Data_List_Creation_Group List Creation/Destruction Functions
113 * Functions that create, initialize and destroy Ecore_Lists.
117 * Create and initialize a new list.
118 * @return A new initialized list on success, @c NULL on failure.
119 * @ingroup Ecore_Data_List_Creation_Group
126 list = (Ecore_List *) malloc(sizeof(Ecore_List));
130 if (!ecore_list_init(list))
140 * Initialize a list to some sane starting values.
141 * @param list The list to initialize.
142 * @return @c TRUE if successful, @c FALSE if an error occurs.
143 * @ingroup Ecore_Data_List_Creation_Group
146 ecore_list_init(Ecore_List * list)
148 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
150 memset(list, 0, sizeof(Ecore_List));
156 * Free a list and all of it's nodes.
157 * @param list The list to be freed.
158 * @ingroup Ecore_Data_List_Creation_Group
161 ecore_list_destroy(Ecore_List * list)
165 CHECK_PARAM_POINTER("list", list);
169 data = _ecore_list_first_remove(list);
171 list->free_func(data);
178 * Set the function for freeing data.
179 * @param list The list that will use this function when nodes are
181 * @param free_func The function that will free the key data.
182 * @return @c TRUE on successful set, @c FALSE otherwise.
185 ecore_list_free_cb_set(Ecore_List * list, Ecore_Free_Cb free_func)
187 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
189 list->free_func = free_func;
195 * Checks the list for any nodes.
196 * @param list The list to check for nodes
197 * @return @c TRUE if no nodes in list, @c FALSE if the list contains nodes
200 ecore_list_empty_is(Ecore_List * list)
204 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
213 * Returns the number of the current node.
214 * @param list The list to return the number of the current node.
215 * @return The number of the current node in the list.
218 ecore_list_index(Ecore_List * list)
222 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
230 * Find the number of nodes in the list.
231 * @param list The list to find the number of nodes
232 * @return The number of nodes in the list.
235 ecore_list_count(Ecore_List * list)
239 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
247 @defgroup Ecore_Data_List_Add_Item_Group List Item Adding Functions
249 Functions that are used to add nodes to an Ecore_List.
253 * Append data to the list.
254 * @param list The list.
255 * @param data The data to append.
256 * @return @c FALSE if an error occurs, @c TRUE if appended successfully
257 * @ingroup Ecore_Data_List_Add_Item_Group
260 ecore_list_append(Ecore_List * list, void *data)
263 Ecore_List_Node *node;
265 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
267 node = ecore_list_node_new();
270 ret = _ecore_list_append_0(list, node);
275 /* For adding items to the end of the list */
277 _ecore_list_append_0(Ecore_List * list, Ecore_List_Node * end)
280 list->last->next = end;
284 if (list->first == NULL)
288 list->current = NULL;
291 if (list->index >= list->nodes)
300 * Prepend data to the beginning of the list.
301 * @param list The list.
302 * @param data The data to prepend.
303 * @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
304 * @ingroup Ecore_Data_List_Add_Item_Group
307 ecore_list_prepend(Ecore_List * list, void *data)
310 Ecore_List_Node *node;
312 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
314 node = ecore_list_node_new();
317 ret = _ecore_list_prepend_0(list, node);
322 /* For adding items to the beginning of the list */
324 _ecore_list_prepend_0(Ecore_List * list, Ecore_List_Node * start)
326 /* Put it at the beginning of the list */
327 start->next = list->first;
331 /* If no last node, then the first node is the last node */
332 if (list->last == NULL)
333 list->last = list->first;
342 * Insert data in front of the current point in the list.
343 * @param list The list to hold the inserted @p data.
344 * @param data The data to insert into @p list.
345 * @return @c FALSE if there is an error, @c TRUE on success
346 * @ingroup Ecore_Data_List_Add_Item_Group
349 ecore_list_insert(Ecore_List * list, void *data)
352 Ecore_List_Node *node;
354 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
356 node = ecore_list_node_new();
359 ret = _ecore_list_insert(list, node);
364 /* For adding items in front of the current position in the list */
366 _ecore_list_insert(Ecore_List * list, Ecore_List_Node * new_node)
369 * If the current point is at the beginning of the list, then it's the
370 * same as prepending it to the list.
372 if (list->current == list->first)
373 return _ecore_list_prepend_0(list, new_node);
375 if (list->current == NULL)
379 ret_value = _ecore_list_append_0(list, new_node);
380 list->current = list->last;
385 /* Setup the fields of the new node */
386 new_node->next = list->current;
388 /* And hook the node into the list */
389 _ecore_list_index_goto(list, ecore_list_index(list) - 1);
391 list->current->next = new_node;
393 /* Now move the current item to the inserted item */
394 list->current = new_node;
402 @defgroup Ecore_Data_List_Remove_Item_Group List Item Removing Functions
404 Functions that remove nodes from an Ecore_List.
408 * Remove the current item from the list.
409 * @param list The list to remove the current item
410 * @return A pointer to the removed data on success, @c NULL on failure.
411 * @ingroup Ecore_Data_List_Remove_Item_Group
414 ecore_list_remove(Ecore_List * list)
418 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
420 ret = _ecore_list_remove_0(list);
425 /* Remove the current item from the list */
427 _ecore_list_remove_0(Ecore_List * list)
430 Ecore_List_Node *old;
435 if (ecore_list_empty_is(list))
441 if (list->current == list->first)
442 return _ecore_list_first_remove(list);
444 if (list->current == list->last)
445 return _ecore_list_last_remove(list);
449 _ecore_list_index_goto(list, list->index - 1);
451 list->current->next = old->next;
456 _ecore_list_next(list);
458 ecore_list_node_destroy(old, NULL);
465 * Remove and free the data in lists current position.
466 * @param list The list to remove and free the current item.
467 * @return @c TRUE on success, @c FALSE on error
468 * @ingroup Ecore_Data_List_Remove_Item_Group
471 ecore_list_remove_destroy(Ecore_List * list)
475 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
477 data = _ecore_list_remove_0(list);
479 list->free_func(data);
485 * Remove the first item from the list.
486 * @param list The list to remove the current item
487 * @return Returns a pointer to the removed data on success, @c NULL on
489 * @ingroup Ecore_Data_List_Remove_Item_Group
492 ecore_list_first_remove(Ecore_List * list)
496 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
498 ret = _ecore_list_first_remove(list);
503 /* Remove the first item from the list */
505 _ecore_list_first_remove(Ecore_List * list)
508 Ecore_List_Node *old;
513 if (ecore_list_empty_is(list))
518 list->first = list->first->next;
520 if (list->current == old)
521 list->current = list->first;
523 (list->index ? list->index-- : 0);
525 if (list->last == old)
526 list->last = list->first;
531 ecore_list_node_destroy(old, NULL);
538 * Remove the last item from the list.
539 * @param list The list to remove the last node from
540 * @return A pointer to the removed data on success, @c NULL on failure.
541 * @ingroup Ecore_Data_List_Remove_Item_Group
544 ecore_list_last_remove(Ecore_List * list)
548 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
550 ret = _ecore_list_last_remove(list);
555 /* Remove the last item from the list */
557 _ecore_list_last_remove(Ecore_List * list)
560 Ecore_List_Node *old, *prev;
565 if (ecore_list_empty_is(list))
569 if (list->current == old)
570 list->current = NULL;
572 if (list->first == old)
574 for (prev = list->first; prev && prev->next != old; prev = prev->next)
584 ecore_list_node_destroy(old, NULL);
591 @defgroup Ecore_Data_List_Traverse_Group List Traversal Functions
593 Functions that can be used to traverse an Ecore_List.
597 * Make the current item the item with the given index number.
598 * @param list The list.
599 * @param indx The position to move the current item.
600 * @return A pointer to new current item on success, @c NULL on failure.
601 * @ingroup Ecore_Data_List_Traverse_Group
604 ecore_list_index_goto(Ecore_List * list, int indx)
608 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
610 ret = _ecore_list_index_goto(list, indx);
615 /* This is the non-threadsafe version, use this inside internal functions that
616 * already lock the list */
618 _ecore_list_index_goto(Ecore_List * list, int indx)
625 if (ecore_list_empty_is(list))
628 if (indx > ecore_list_count(list) || indx < 0)
631 _ecore_list_first_goto(list);
633 for (i = 0; i < indx && _ecore_list_next(list); i++)
636 if (i >= list->nodes)
641 return list->current->data;
645 * Make the current item the node that contains @p data.
646 * @param list The list.
647 * @param data The data to find.
648 * @return A pointer to @p data on success, @c NULL on failure.
649 * @ingroup Ecore_Data_List_Traverse_Group
652 ecore_list_goto(Ecore_List * list, const void *data)
656 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
658 ret = _ecore_list_goto(list, data);
663 /* Set the current position to the node containing data */
665 _ecore_list_goto(Ecore_List * list, const void *data)
668 Ecore_List_Node *node;
676 while (node && node->data)
678 Ecore_List_Node *next;
680 if (node->data == data)
693 list->current = node;
696 return list->current->data;
700 * Make the current item the first item in the list
701 * @param list The list.
702 * @return A pointer to the first item on success, @c NULL on failure
703 * @ingroup Ecore_Data_List_Traverse_Group
706 ecore_list_first_goto(Ecore_List * list)
710 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
712 ret = _ecore_list_first_goto(list);
717 /* Set the current position to the start of the list */
719 _ecore_list_first_goto(Ecore_List * list)
724 list->current = list->first;
727 return list->current->data;
731 * Make the current item the last item in the list.
732 * @param list The list.
733 * @return A pointer to the last item on success, @c NULL on failure.
734 * @ingroup Ecore_Data_List_Traverse_Group
737 ecore_list_last_goto(Ecore_List * list)
741 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
743 ret = _ecore_list_last_goto(list);
748 /* Set the current position to the end of the list */
750 _ecore_list_last_goto(Ecore_List * list)
752 if (!list || !list->last)
755 list->current = list->last;
756 list->index = (list->nodes - 1);
758 return list->current->data;
762 * Retrieve the data pointed to by the current item in @p list.
763 * @param list The list.
764 * @return Returns the data at current position, can be @c NULL.
767 ecore_list_current(Ecore_List * list)
771 ret = _ecore_list_current(list);
776 /* Return the data of the current node without incrementing */
778 _ecore_list_current(Ecore_List * list)
782 if (!list || !list->current)
785 ret = list->current->data;
791 * Retrieve the data pointed to by the current item, and make the next item
793 * @param list The list to retrieve data from.
794 * @return The current item in the list on success, @c NULL on failure.
797 ecore_list_next(Ecore_List * list)
801 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
803 data = _ecore_list_next(list);
808 /* Return the data contained in the current node and go to the next node */
810 _ecore_list_next(Ecore_List * list)
813 Ecore_List_Node *ret;
814 Ecore_List_Node *next;
820 next = list->current->next;
822 list->current = next;
831 * Remove all nodes from @p list.
832 * @param list The list.
833 * @return Returns @c TRUE on success, @c FALSE on error.
834 * @note The data for each item on the list is not freed by
835 * @c ecore_list_clear().
838 ecore_list_clear(Ecore_List * list)
840 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
842 while (!ecore_list_empty_is(list))
843 _ecore_list_first_remove(list);
849 * Execute function for each node in @p list.
850 * @param list The list.
851 * @param function The function to pass each node from @p list to.
852 * @return Returns @c TRUE on success, @c FALSE on failure.
853 * @ingroup Ecore_Data_List_Traverse_Group
856 ecore_list_for_each(Ecore_List * list, Ecore_For_Each function, void *user_data)
860 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
862 ret = _ecore_list_for_each(list, function, user_data);
867 /* The real meat of executing the function for each data node */
869 _ecore_list_for_each(Ecore_List * list, Ecore_For_Each function,
872 Ecore_List_Node *node, *next;
877 for (node = list->first; node; node = next)
880 function(node->data, user_data);
887 * Find data in @p list using the compare function @p func
888 * @param list The list.
889 * @param function The function to test each node of @p list with
890 * @param user_data Data to match against (used by @p function)
891 * @return the first matching data node, or NULL if none match
894 ecore_list_find(Ecore_List * list, Ecore_Compare_Cb function,
895 const void *user_data)
897 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
899 return _ecore_list_find(list, function, user_data);
902 /* The real meat of finding a node via a compare cb */
904 _ecore_list_find(Ecore_List * list, Ecore_Compare_Cb function,
905 const void *user_data)
907 Ecore_List_Node *node, *next;
912 for (node = list->first; node; node = next)
915 if (!function(node->data, user_data))
922 /* Initialize a node to starting values */
924 ecore_list_node_init(Ecore_List_Node * node)
926 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
935 @defgroup Ecore_Data_List_Node_Group List Node Functions
937 Functions that are used in the creation, maintenance and destruction of
942 * Allocates and initializes a new list node.
943 * @return A new Ecore_List_Node on success, @c NULL otherwise.
944 * @ingroup Ecore_Data_List_Node_Group
946 EAPI Ecore_List_Node *
947 ecore_list_node_new(void)
949 Ecore_List_Node *new_node;
951 new_node = (Ecore_List_Node *) malloc(sizeof(Ecore_List_Node));
953 if (!ecore_list_node_init(new_node))
963 * Calls the function to free the data and the node.
964 * @param node Node to destroy.
965 * @param free_func Function to call if @p node points to data to free.
967 * @ingroup Ecore_Data_List_Node_Group
970 ecore_list_node_destroy(Ecore_List_Node * node, Ecore_Free_Cb free_func)
972 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
974 if (free_func && node->data)
975 free_func(node->data);
982 #endif /* !USE_ECORE */
989 ecore_list_node_remove(Ecore_List * list, void *_data)
993 data = ecore_list_goto(list, _data);
995 ecore_list_remove(list);
1001 ecore_list_items_get(Ecore_List * list, int *pnum)
1007 num = ecore_list_count(list);
1011 lst = (void **)malloc(num * sizeof(void *));
1015 for (i = 0, ecore_list_first_goto(list);
1016 (b = ecore_list_next(list)) != NULL;)