#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdlib.h>

#include "Evas_Data.h"
#include <evas_mempool.h>

typedef struct _Evas_List_Accounting Evas_List_Accounting;

struct _Evas_List_Accounting
{
   Evas_List *last;
   int count;
};

static int _evas_list_alloc_error = 0;

static Evas_Mempool _evas_list_mempool =
{
   sizeof(Evas_List),
   320,
   0, NULL, NULL
};
static Evas_Mempool _evas_list_accounting_mempool =
{
   sizeof(Evas_List_Accounting),
   80,
   0, NULL, NULL
};

/**
 * @defgroup Evas_List_Data_Group Linked List Creation Functions
 *
 * Functions that add data to an Evas_List.
 */

/**
 * Appends the given data to the given linked list.
 *
 * The following example code demonstrates how to ensure that the
 * given data has been successfully appended.
 *
 * @code
 * Evas_List *list = NULL;
 * extern void *my_data;
 *
 * list = evas_list_append(list, my_data);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * @endcode
 *
 * @param   list The given list.  If @c NULL is given, then a new list
 *               is created.
 * @param   data The data to append.
 * @return  A new list pointer that should be used in place of the one
 *          given to this function if successful.  Otherwise, the old
 *          pointer is returned.
 * @ingroup Evas_List_Data_Group
 */
EAPI Evas_List *
evas_list_append(Evas_List *list, const void *data)
{
   Evas_List *l, *new_l;

   _evas_list_alloc_error = 0;
   new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List));
   if (!new_l)
     {
        _evas_list_alloc_error = 1;
        return list;
     }

   new_l->next = NULL;
   new_l->data = (void *)data;
   if (!list)
     {
        new_l->prev = NULL;
        new_l->accounting = evas_mempool_malloc(&_evas_list_accounting_mempool,
                                                sizeof(Evas_List_Accounting));
        if (!new_l->accounting)
          {
             _evas_list_alloc_error = 1;
             evas_mempool_free(&_evas_list_mempool, new_l);
             return list;
          }

        new_l->accounting->last = new_l;
        new_l->accounting->count = 1;
        return new_l;
     }

   l = list->accounting->last;
   l->next = new_l;
   new_l->prev = l;
   new_l->accounting = list->accounting;
   list->accounting->last = new_l;
   list->accounting->count++;
   return list;
}

/**
 * Prepends the given data to the given linked list.
 *
 * The following example code demonstrates how to ensure that the
 * given data has been successfully prepended.
 *
 * Example:
 * @code
 * Evas_List *list = NULL;
 * extern void *my_data;
 *
 * list = evas_list_prepend(list, my_data);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * @endcode
 *
 * @param   list The given list.
 * @param   data The given data.
 * @return  A new list pointer that should be used in place of the one
 *          given to this function, if successful.  Otherwise, the old
 *          pointer is returned.
 * @ingroup Evas_List_Data_Group
 */
EAPI Evas_List *
evas_list_prepend(Evas_List *list, const void *data)
{
   Evas_List *new_l;

   _evas_list_alloc_error = 0;
   new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List));
   if (!new_l)
     {
        _evas_list_alloc_error = 1;
        return list;
     }

   new_l->prev = NULL;
   new_l->data = (void *)data;
   if (!list)
     {
        new_l->next = NULL;
        new_l->accounting = evas_mempool_malloc(&_evas_list_accounting_mempool,
                                                sizeof(Evas_List_Accounting));
        if (!new_l->accounting)
          {
             _evas_list_alloc_error = 1;
             evas_mempool_free(&_evas_list_mempool, new_l);
             return list;
          }

        new_l->accounting->last = new_l;
        new_l->accounting->count = 1;
        return new_l;
     }

   new_l->next = list;
   list->prev = new_l;
   new_l->accounting = list->accounting;
   list->accounting->count++;
   return new_l;
}

/**
 * Inserts the given data into the given linked list after the specified data.
 *
 * If @p relative is not in the list, @p data is appended to the end of the
 * list.  If there are multiple instances of @p relative in the list,
 * @p data is inserted after the first instance.
 *
 * The following example code demonstrates how to ensure that the
 * given data has been successfully inserted.
 *
 * @code
 * Evas_List *list = NULL;
 * extern void *my_data;
 * extern void *relative_member;
 *
 * list = evas_list_append(list, relative_member);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * list = evas_list_append_relative(list, my_data, relative_member);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * @endcode
 *
 * @param   list The given linked list.
 * @param   data The given data.
 * @param   relative The data to insert after.
 * @return  A new list pointer that should be used in place of the one
 *          given to this function if successful.  Otherwise, the old pointer
 *          is returned.
 * @ingroup Evas_List_Data_Group
 */
EAPI Evas_List *
evas_list_append_relative(Evas_List *list,
                          const void *data,
                          const void *relative)
{
   Evas_List *l;

   for (l = list; l; l = l->next)
     {
        if (l->data == relative)
           return evas_list_append_relative_list(list, data, l);
     }
   return evas_list_append(list, data);
}

EAPI Evas_List *
evas_list_append_relative_list(Evas_List *list,
                               const void *data,
                               Evas_List *relative)
{
   Evas_List *new_l;

   if ((!list) || (!relative))
      return evas_list_append(list, data);

   _evas_list_alloc_error = 0;
   new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List));
   if (!new_l)
     {
        _evas_list_alloc_error = 1;
        return list;
     }

   new_l->data = (void *)data;
   if (relative->next)
     {
        new_l->next = relative->next;
        relative->next->prev = new_l;
     }
   else
      new_l->next = NULL;

   relative->next = new_l;
   new_l->prev = relative;
   new_l->accounting = list->accounting;
   list->accounting->count++;
   if (!new_l->next)
      new_l->accounting->last = new_l;

   return list;
}

/**
 * Prepend a data pointer to a linked list before the member specified
 * @param list The list handle to prepend @p data too
 * @param data The data pointer to prepend to list @p list before @p relative
 * @param relative The data pointer before which to insert @p data
 * @return A new list handle to replace the old one

 * Inserts the given data into the given linked list before the member
 * specified.
 *
 * If @p relative is not in the list, @p data is prepended to the
 * start of the list.  If there are multiple instances of @p relative
 * in the list, @p data is inserted before the first instance.
 *
 * The following code example demonstrates how to ensure that the
 * given data has been successfully inserted.
 *
 * @code
 * Evas_List *list = NULL;
 * extern void *my_data;
 * extern void *relative_member;
 *
 * list = evas_list_append(list, relative_member);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * list = evas_list_prepend_relative(list, my_data, relative_member);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * @endcode
 *
 * @param   list The given linked list.
 * @param   data The given data.
 * @param   relative The data to insert before.
 * @return  A new list pointer that should be used in place of the one
 *          given to this function if successful.  Otherwise the old pointer
 *          is returned.
 * @ingroup Evas_List_Data_Group
 */
EAPI Evas_List *
evas_list_prepend_relative(Evas_List *list,
                           const void *data,
                           const void *relative)
{
   Evas_List *l;

   _evas_list_alloc_error = 0;
   for (l = list; l; l = l->next)
     {
        if (l->data == relative)
           return evas_list_prepend_relative_list(list, data, l);
     }
   return evas_list_prepend(list, data);
}

EAPI Evas_List *
evas_list_prepend_relative_list(Evas_List *list,
                                const void *data,
                                Evas_List *relative)
{
   Evas_List *new_l;

   if ((!list) || (!relative))
      return evas_list_prepend(list, data);

   _evas_list_alloc_error = 0;
   new_l = evas_mempool_malloc(&_evas_list_mempool, sizeof(Evas_List));
   if (!new_l)
     {
        _evas_list_alloc_error = 1;
        return list;
     }

   new_l->data = (void *)data;
   new_l->prev = relative->prev;
   new_l->next = relative;
   if (relative->prev)
      relative->prev->next = new_l;

   relative->prev = new_l;
   new_l->accounting = list->accounting;
   list->accounting->count++;
   if (new_l->prev)
      return list;

   return new_l;
}

/**
 * @defgroup Evas_List_Remove_Group Linked List Remove Functions
 *
 * Functions that remove data from linked lists.
 */

/**
 * Removes the first instance of the specified data from the given list.
 *
 * If the specified data is not in the given list, nothing is done.
 *
 * @param   list The given list.
 * @param   data The specified data.
 * @return  A new list pointer that should be used in place of the one
 *          passed to this functions.
 * @ingroup Evas_List_Remove_Group
 */
EAPI Evas_List *
evas_list_remove(Evas_List *list, const void *data)
{
   Evas_List *l;

   for (l = list; l; l = l->next)
     {
        if (l->data == data)
           return evas_list_remove_list(list, l);
     }
   return list;
}

/**
 * Removes the specified data
 *
 * Remove a specified member from a list
 * @param list The list handle to remove @p remove_list from
 * @param remove_list The list node which is to be removed
 * @return A new list handle to replace the old one
 *
 * Calling this function takes the list node @p remove_list and removes it
 * from the list @p list, freeing the list node structure @p remove_list.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * Evas_List *l;
 * extern void *my_data;
 *
 * for (l = list; l; l= l->next)
 *   {
 *     if (l->data == my_data)
 *       {
 *         list = evas_list_remove_list(list, l);
 *         break;
 *       }
 *   }
 * @endcode
 * @ingroup Evas_List_Remove_Group
 */
EAPI Evas_List *
evas_list_remove_list(Evas_List *list, Evas_List *remove_list)
{
   Evas_List *return_l;

   if (!list)
      return NULL;

   if (!remove_list)
      return list;

   if (remove_list->next)
      remove_list->next->prev = remove_list->prev;

   if (remove_list->prev)
     {
        remove_list->prev->next = remove_list->next;
        return_l = list;
     }
   else
      return_l = remove_list->next;

   if (remove_list == list->accounting->last)
      list->accounting->last = remove_list->prev;

   list->accounting->count--;
   if (list->accounting->count == 0)
     {
        evas_mempool_free(&_evas_list_accounting_mempool, list->accounting);
     }
   evas_mempool_free(&_evas_list_mempool,            remove_list);
   return return_l;
}

/**
 * Moves the specified data to the head of the list
 *
 * Move a specified member to the head of the list
 * @param list The list handle to move @p inside
 * @param move_list The list node which is to be moved
 * @return A new list handle to replace the old one
 *
 * Calling this function takes the list node @p move_list and moves it
 * to the front of the @p list.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * Evas_List *l;
 * extern void *my_data;
 *
 * for (l = list; l; l= l->next)
 *   {
 *     if (l->data == my_data)
 *       {
 *         list = evas_list_promote_list(list, l);
 *         break;
 *       }
 *   }
 * @endcode
 * @ingroup Evas_List_Promote_Group
 */
EAPI Evas_List *
evas_list_promote_list(Evas_List *list, Evas_List *move_list)
{
   Evas_List *return_l;

   if (!list)
      return NULL;

   if (!move_list)
      return list;

   if (move_list == list)
      return list;

   if (move_list->next)
      move_list->next->prev = move_list->prev;

   if (move_list->prev)
     {
        move_list->prev->next = move_list->next;
        return_l = list;
     }
   else
      return_l = move_list->next;

   if (move_list == list->accounting->last)
      list->accounting->last = move_list->prev;

   move_list->prev = return_l->prev;
   if (return_l->prev)
      return_l->prev->next = move_list;

   return_l->prev = move_list;
   move_list->next = return_l;
   return move_list;
}



/**
 * @defgroup Evas_List_Find_Group Linked List Find Functions
 *
 * Functions that find specified data in a linked list.
 */

/**
 * Find a member of a list and return the member
 * @param list The list handle to search for @p data
 * @param data The data pointer to find in the list @p list
 * @return The found member data pointer
 *
 * A call to this function will search the list @p list from beginning to end
 * for the first member whose data pointer is @p data. If it is found, @p data
 * will be returned, otherwise NULL will be returned.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * extern void *my_data;
 *
 * if (evas_list_find(list, my_data) == my_data)
 *   {
 *     printf("Found member %p\n", my_data);
 *   }
 * @endcode
 * @ingroup Evas_List_Find_Group
 */
EAPI void *
evas_list_find(const Evas_List *list, const void *data)
{
   const Evas_List *l;

   for (l = list; l; l = l->next)
     {
        if (l->data == data)
           return (void *)data;
     }
   return NULL;
}

/**
 * Find a member of a list and return the list node containing that member
 * @param list The list handle to search for @p data
 * @param data The data pointer to find in the list @p list
 * @return The found members list node
 *
 * A call to this function will search the list @p list from beginning to end
 * for the first member whose data pointer is @p data. If it is found, the
 * list node containing the specified member will be returned, otherwise NULL
 * will be returned.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * extern void *my_data;
 * Evas_List *found_node;
 *
 * found_node = evas_list_find_list(list, my_data);
 * if (found_node)
 *   {
 *     printf("Found member %p\n", found_node->data);
 *   }
 * @endcode
 * @ingroup Evas_List_Find_Group
 */
EAPI Evas_List *
evas_list_find_list(const Evas_List *list, const void *data)
{
   const Evas_List *l;

   for (l = list; l; l = l->next)
     {
        if (l->data == data)
           return (Evas_List *)l;
     }
   return NULL;
}

/**
 * Free an entire list and all the nodes, ignoring the data contained
 * @param list The list to free
 * @return A NULL pointer
 *
 * This function will free all the list nodes in list specified by @p list.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 *
 * list = evas_list_free(list);
 * @endcode
 * @ingroup Evas_List_Remove_Group
 */
EAPI Evas_List *
evas_list_free(Evas_List *list)
{
   Evas_List *l, *free_l;

   if (!list)
      return NULL;

             evas_mempool_free(&_evas_list_accounting_mempool, list->accounting);
   for (l = list; l; )
     {
        free_l = l;
        l = l->next;
             evas_mempool_free(&_evas_list_mempool, free_l);
     }
   return NULL;
}

/**
 * @defgroup Evas_List_Traverse_Group Linked List Traverse Functions
 *
 * Functions that you can use to traverse a linked list.
 */

/**
 * Get the last list node in the list
 * @param list The list to get the last list node from
 * @return The last list node in the list @p list
 *
 * This function will return the last list node in the list (or NULL if the
 * list is empty).
 *
 * NB: This is a order-1 operation (it takes the same short time regardless of
 * the length of the list).
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * Evas_List *last, *l;
 *
 * last = evas_list_last(list);
 * printf("The list in reverse:\n");
 * for (l = last; l; l = l->prev)
 *   {
 *     printf("%p\n", l->data);
 *   }
 * @endcode
 * @ingroup Evas_List_Traverse_Group
 */
EAPI Evas_List *
evas_list_last(const Evas_List *list)
{
   if (!list)
      return NULL;

   return list->accounting->last;
}

/**
 * Get the next list node after the specified list node
 * @param list The list node to get the next list node from
 * @return The next list node, or NULL if no next list node exists
 *
 * This function returns the next list node after the current one. It is
 * equivalent to list->next.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * Evas_List *l;
 *
 * printf("The list:\n");
 * for (l = list; l; l = evas_list_next(l))
 *   {
 *     printf("%p\n", l->data);
 *   }
 * @endcode
 * @ingroup Evas_List_Traverse_Group
 */
EAPI Evas_List *
evas_list_next(const Evas_List *list)
{
   if (!list)
      return NULL;

   return list->next;
}

/**
 * Get the previous list node before the specified list node
 * @param list The list node to get the previous list node from
 * @return The previous list node, or NULL if no previous list node exists
 *
 * This function returns the previous list node before the current one. It is
 * equivalent to list->prev.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * Evas_List *last, *l;
 *
 * last = evas_list_last(list);
 * printf("The list in reverse:\n");
 * for (l = last; l; l = evas_list_prev(l))
 *   {
 *     printf("%p\n", l->data);
 *   }
 * @endcode
 * @ingroup Evas_List_Traverse_Group
 */
EAPI Evas_List *
evas_list_prev(const Evas_List *list)
{
   if (!list)
      return NULL;

   return list->prev;
}

/**
 * @defgroup Evas_List_General_Group Linked List General Functions
 *
 * Miscellaneous functions that work on linked lists.
 */

/**
 * Get the list node data member
 * @param list The list node to get the data member of
 * @return The data member from the list node @p list
 *
 * This function returns the data member of the specified list node @p list.
 * It is equivalent to list->data.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * Evas_List *l;
 *
 * printf("The list:\n");
 * for (l = list; l; l = evas_list_next(l))
 *   {
 *     printf("%p\n", evas_list_data(l));
 *   }
 * @endcode
 * @ingroup Evas_List_General_Group
 */
EAPI void *
evas_list_data(const Evas_List *list)
{
   if (!list)
      return NULL;

   return list->data;
}

/**
 * Get the count of the number of items in a list
 * @param list The list whose count to return
 * @return The number of members in the list @p list
 *
 * This function returns how many members in the specified list: @p list. If
 * the list is empty (NULL), 0 is returned.
 *
 * NB: This is an order-1 operation and takes the same time regardless of the
 * length of the list.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 *
 * printf("The list has %i members\n", evas_list_count(list));
 * @endcode
 * @ingroup Evas_List_General_Group
 */
EAPI int
evas_list_count(const Evas_List *list)
{
   if (!list)
      return 0;

   return list->accounting->count;
}

/**
 * Get the nth member's data pointer in a list
 * @param list The list to get member number @p n from
 * @param n The number of the element (0 being the first)
 * @return The data pointer stored in the specified element
 *
 * This function returns the data pointer of element number @p n, in the list
 * @p list. The first element in the array is element number 0. If the element
 * number @p n does not exist, NULL will be returned.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * extern int number;
 * void *data;
 *
 * data = evas_list_nth(list, number);
 * if (data)
 *   printf("Element number %i has data %p\n", number, data);
 * @endcode
 * @ingroup Evas_List_Find_Group
 */
EAPI void *
evas_list_nth(const Evas_List *list, int n)
{
   Evas_List *l;

   l = evas_list_nth_list(list, n);
   return l ? l->data : NULL;
}

/**
 * Get the nth member's list node in a list
 * @param list The list to get member number @p n from
 * @param n The number of the element (0 being the first)
 * @return The list node stored in the numbered element
 *
 * This function returns the list node of element number @p n, in the list
 * @p list. The first element in the array is element number 0. If the element
 * number @p n does not exist, NULL will be returned.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 * extern int number;
 * Evas_List *nth_list;
 *
 * nth_list = evas_list_nth_list(list, number);
 * if (nth_list)
 *   printf("Element number %i has data %p\n", number, nth_list->data);
 * @endcode
 * @ingroup Evas_List_Find_Group
 */
EAPI Evas_List *
evas_list_nth_list(const Evas_List *list, int n)
{
   int i;
   const Evas_List *l;

   /* check for non-existing nodes */
   if ((!list) || (n < 0) ||
       (n > (list->accounting->count - 1)))
      return NULL;

   /* if the node is in the 2nd half of the list, search from the end
    * else, search from the beginning.
    */
   if (n > (list->accounting->count / 2))
      for (i = list->accounting->count - 1,
           l = list->accounting->last;
           l;
           l = l->prev, i--)
        {
           if (i == n)
              return (Evas_List *)l;
        }
   else
      for (i = 0, l = list; l; l = l->next, i++)
        {
           if (i == n)
              return (Evas_List *)l;
        }

   return NULL;
}

/**
 * @defgroup Evas_List_Ordering_Group Linked List Ordering Functions
 *
 * Functions that change the ordering of data in a linked list.
 */

/**
 * Reverse all the elements in the list
 * @param list The list to reverse
 * @return The list after it has been reversed
 *
 * This takes a list @p list, and reverses the order of all elements in the
 * list, so the last member is now first, and so on.
 *
 * Example:
 * @code
 * extern Evas_List *list;
 *
 * list = evas_list_reverse(list);
 * @endcode
 * @ingroup Evas_List_Ordering_Group
 */
EAPI Evas_List *
evas_list_reverse(Evas_List *list)
{
   Evas_List *l1, *l2;

   if (!list)
      return NULL;

   l1 = list;
   l2 = list->accounting->last;
   while (l1 != l2)
     {
        void *data;

        data = l1->data;
        l1->data = l2->data;
        l2->data = data;
        l1 = l1->next;
        if (l1 == l2)
           break;

        l2 = l2->prev;
     }

   return list;
}

/**
 * Sort a list according to the ordering func will return
 * @param list The list handle to sort
 * @param size The length of the list to sort
 * @param func A function pointer that can handle comparing the list data
 * nodes
 * @return A new sorted list
 *
 * This function sorts your list.  The data in your nodes can be arbitrary,
 * you just have to be smart enough to know what kind of data is in your
 * lists
 *
 * Example:
 * @code
 * int
 * sort_cb(void *d1, void *d2)
 * {
 *   const char *txt = NULL;
 *    const char *txt2 = NULL;
 *
 *    if(!d1) return(1);
 *    if(!d2) return(-1);
 *
 *    return(strcmp((const char*)d1, (const char*)d2));
 * }
 * extern Evas_List *list;
 *
 * list = evas_list_sort(list, evas_list_count(list), sort_cb);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List Sorting failed.\n");
 *     exit(-1);
 *   }
 * @endcode
 * @ingroup Evas_List_Ordering_Group
 */
EAPI Evas_List *
evas_list_sort(Evas_List *list, int size, int (*func)(void *, void *))
{
   Evas_List *last;
   unsigned int list_number;
   unsigned int middle;
   unsigned int list_size;

   if (!list || !func)
      return NULL;

   /* if the caller specified an invalid size, sort the whole list */
   if ((size <= 0) ||
       (size > list->accounting->count))
      size = list->accounting->count;

   last = list->accounting->last;
   middle = size - size / 2;

   for (list_number = middle, list_size = 1;
        list_size < middle * 2;
        list_number >>= 1, list_size <<= 1)
     {
        Evas_List *head1 = list;
        unsigned int limit = size;
        unsigned int process_list;
        unsigned int pass_number;
        unsigned int split_size = list_size;

        for (process_list = 0; process_list < list_number + 1; ++process_list)
          {
             Evas_List *head2;
             unsigned int size_sum;
             int size1, size2;
             int i;

             size1 = limit < split_size ? limit : split_size;
             limit -= size1;

             size2 = limit < split_size ? limit : split_size;
             limit -= size2;

             size_sum = size1 + size2;

             for (head2 = head1, i = 0; i < size1; ++i)
                head2 = evas_list_next (head2);

             for (pass_number = 0; pass_number < size_sum; ++pass_number)
               {
                  Evas_List *next;
                  Evas_List *prev1;
                  Evas_List *prev2;

                  if (size1 == 0 || !head1) /* List1 is empty, head1 is already at the end of the list. So only need to update head2 */
                    {
                       for (; pass_number < size_sum; ++pass_number)
                          head2 = evas_list_next (head2);
                       break;
                    }
                  else
                  if (size2 == 0 || !head2) /* List2 is empty, just leave */
                     break;
                  else
                  if (func (head1->data, head2->data) < 0)
                    {
                       head1 = evas_list_next (head1);
                       --size1;
                    }
                  else
                    {
                       next = evas_list_next (head2);
                       prev1 = evas_list_prev (head1);
                       prev2 = evas_list_prev (head2);

                       if (next)
                          next->prev = prev2;

                       if (prev1)
                          prev1->next = head2;

                       if (prev2)
                          prev2->next = next;

                       head2->prev = prev1;
                       head2->next = head1;
                       head1->prev = head2;

                       --size2;

                       if (head1 == list)
                          list = head2;

                       if (head2 == last)
                          last = prev2;

                       head2 = next;
                    }
               }
             head1 = head2;
          }
     }

   list->accounting->last = last;
   return list;
}
/**
 * Return the memory allocation failure flag after any operation needin allocation
 * @return The state of the allocation flag
 *
 * This function returns the state of the memory allocation flag. This flag is
 * set if memory allocations during evas_list_append(), evas_list_prepend(),
 * evas_list_append_relative(), or evas_list_prepend_relative() fail. If they
 * do fail, 1 will be returned, otherwise 0 will be returned. The flag will
 * remain in its current state until the next call that requires allocation
 * is called, and is then reset.
 *
 * Example:
 * @code
 * Evas_List *list = NULL;
 * extern void *my_data;
 *
 * list = evas_list_append(list, my_data);
 * if (evas_list_alloc_error())
 *   {
 *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
 *     exit(-1);
 *   }
 * @endcode
 * @ingroup Evas_List_General_Group
 */
EAPI int
evas_list_alloc_error(void)
{
   return _evas_list_alloc_error;
}
