/****************************************************/
/* Gestion de listes doublement chainees */
/* list.c */
/* */
/* Ecrit par : Daniel Lacroix (all rights reserved) */
/* */
/****************************************************/
#include <stdlib.h>
#include <list.h>
#include <stdio.h>
/*****************************************************/
/* Rajoute en tete de la liste pList l'element data. */
/* Renvoie le nouveau point d'entree de la liste. */
List *list_prepend(List *pList, pointer data)
{ List *vList;
/* on alloue la memoire pour le nouvel element */
if((vList = (List *)malloc(sizeof(List))) == NULL)
{ perror("malloc failed "); exit(1); }
if(pList == NULL)
{ /* la liste est vide */
vList->data = data;
vList->prev = vList;
vList->next = vList;
} else {
/* il y a deja au moins un element dans la liste */
vList->data = data;
vList->prev = pList->prev;
vList->next = pList;
pList->prev->next = vList;
pList->prev = vList;
}
return(vList);
}
/*****************************************************/
/******************************************************/
/* Rajoute en queue de la liste pList l'element data. */
/* Renvoie le nouveau point d'entree de la liste. */
List *list_append(List *pList, pointer data)
{ List *vList;
/* on alloue la memoire pour le nouvelle element */
if((vList = (List *)malloc(sizeof(List))) == NULL)
{ perror("malloc failed "); exit(1); }
if(pList == NULL)
{ /* la liste est vide */
vList->data = data;
vList->prev = vList;
vList->next = vList;
return(vList);
} else {
/* il y a deja au moins un element dans la liste */
vList->data = data;
vList->prev = pList->prev;
vList->next = pList;
pList->prev->next = vList;
pList->prev = vList;
return(pList);
}
}
/******************************************************/
/**************************************/
/* Libere la liste (pas les elements) */
void list_free(List *pList)
{ List *vListMove,*vListMoveNext;
vListMove = pList;
while(!list_is_end(pList,vListMove))
{
vListMoveNext = list_next(pList,vListMove);
free(vListMove);
vListMove = vListMoveNext;
}
}
/**************************************/
/*************************************************************************/
/* Libere la liste et appele la procedure free_func pour chaque elements */
void list_free_full(List *pList, void (* free_func)(pointer data))
{ List *vListMove,*vListMoveNext;
vListMove = pList;
while(!list_is_end(pList,vListMove))
{
vListMoveNext = list_next(pList,vListMove);
free_func(vListMove->data);
free(vListMove);
vListMove = vListMoveNext;
}
}
/*************************************************************************/
/***************************************************************************/
/* Libere la liste et appele la procedure free (du C) pour chaque elements */
void list_free_full_simple(List *pList)
{ List *vListMove,*vListMoveNext;
vListMove = pList;
while(!list_is_end(pList,vListMove))
{
vListMoveNext = list_next(pList,vListMove);
if(vListMove->data != NULL) free(vListMove->data);
free(vListMove);
vListMove = vListMoveNext;
}
}
/***************************************************************************/
/*****************************************************/
/* Renvoi le nombre d'element contenue dans la liste */
/* Cette operation est realisee par comptage. */
uint32 list_nb_item(List *pList)
{ List *vListMove;
uint32 compteur = 0;
vListMove = pList;
while(!list_is_end(pList,vListMove))
{
compteur++;
list_move_next(pList,vListMove);
}
return(compteur);
}
/*****************************************************/
/************************************************************************************/
/* Libere un element de la liste (pas ce que l'element pointe si c'est un pointeur) */
/* Renvoie le nouveau point d'entree de la liste. */
List *list_free_item(List *pList, pointer data)
{ List *vListMove,*vListMoveNext;
/* on parcourt la liste pList a la recherche de l'element a supprimer */
vListMove = pList;
while(!list_is_end(pList,vListMove) && (vListMove->data != data))
{ list_move_next(pList,vListMove); }
/* si on a trouve l'element, on le libere */
if(!list_is_end(pList,vListMove))
{
/* si il n'y a que notre element dans la liste */
if(vListMove->next == vListMove)
{ /* on libere l'element */
free(vListMove);
/* on renvoie une liste vide */
return(NULL);
} else {
/* on recupere l'element qui suit celui que l'on veut supprimer */
vListMoveNext = vListMove->next;
/* on chaine l'element precedent avec celui qui suit */
vListMove->prev->next = vListMoveNext;
vListMoveNext->prev = vListMove->prev;
/* on libere l'element a liberer */
free(vListMove);
if(pList == vListMove)
{
/* l'element a supprimer etait le premier, c'est */
/* donc le suivant qui devient le premier */
return(vListMoveNext);
} else {
/* l'element a supprimer n'etait pas le premier. */
/* le premiere element de la liste ne change donc pas. */
return(pList);
}
}
}
/* si on est ici c'est l'element a supprimer n'existe */
/* pas dans la liste. on rend donc la liste intacte. */
return(pList);
}
/************************************************************************************/
/************************************************************************************/
/* Libere un element de la liste (pas ce que l'element pointe si c'est un pointeur) */
/* Si l'element a ete libere alors done == TRUE sinon FALSE. */
/* Renvoie le nouveau point d'entree de la liste. */
List *list_free_item_with_check(List *pList, pointer data, boolean *done)
{ List *vListMove,*vListMoveNext;
/* on parcourt la liste pList a la recherche de l'element a supprimer */
vListMove = pList;
while(!list_is_end(pList,vListMove) && (vListMove->data != data))
{ list_move_next(pList,vListMove); }
/* si on a trouve l'element, on le libere */
if(!list_is_end(pList,vListMove))
{
/* on signal que l'element a bien etait trouve */
*done = TRUE;
/* si il n'y a que notre element dans la liste */
if(vListMove->next == vListMove)
{ /* on libere l'element */
free(vListMove);
/* on renvoie une liste vide */
return(NULL);
} else {
/* on recupere l'element qui suit celui que l'on veut supprimer */
vListMoveNext = vListMove->next;
/* on chaine l'element precedent avec celui qui suit */
vListMove->prev->next = vListMoveNext;
vListMoveNext->prev = vListMove->prev;
/* on libere l'element a liberer */
free(vListMove);
if(pList == vListMove)
{
/* l'element a supprimer etait le premier, c'est */
/* donc le suivant qui devient le premier */
return(vListMoveNext);
} else {
/* l'element a supprimer n'etait pas le premier. */
/* le premiere element de la liste ne change donc pas. */
return(pList);
}
}
}
/* si on est ici c'est l'element a supprimer n'existe pas dans la liste.*/
/* on signal de fait que l'on n'a pas trouve l'element cherche. */
*done = FALSE;
/* on rend donc la liste intacte. */
return(pList);
}
/************************************************************************************/
/***************************************************************/
/* Renvoie l'element a la position item_nb dans la liste pList */
/* Si l'element item_nb n'exite pas, la fonction renvoi NULL. */
/* item_nb commence a 1. */
pointer list_item(List *pList, uint32 item_nb)
{ List *vListMove;
uint32 offset=0;
vListMove = pList;
while(!list_is_end(pList,vListMove) && (offset<item_nb-1))
{ list_move_next(pList,vListMove); offset++; }
if(!list_is_end(pList,vListMove))
{ /* si il y a bien un element a la position demande, on le renvoie */
return(vListMove->data);
} else {
/* si on c'est retrouve a la fin de la liste, il n'y a pas d'element */
/* a la postion demande. On renvoie donc NULL pour le signaler */
return(NULL);
}
}
/***************************************************************/
/*******************************************************************/
/* Rajoute un element apres l'element before. Si l'element before */
/* n'est pas trouve alors le nouvel element sera rajoute a la fin. */
/* Renvoie ne nouveau point d'entree de la liste pList. */
List *list_insert_after_item(List *pList, pointer before, pointer data)
{ List *vList;
List *vListMove;
/* on alloue la memoire pour le nouvelle element */
if((vList = (List *)malloc(sizeof(List))) == NULL)
{ perror("malloc failed "); exit(1); }
vListMove = pList;
while(!list_is_end(pList,vListMove) && (vListMove->data != before))
{ list_move_next(pList,vListMove); }
/* si on a trouve l'element precedent */
if(!list_is_end(pList,vListMove))
{
vList->data = data;
vList->prev = vListMove;
vList->next = vListMove->next;
vListMove->next = vList;
vList->next->prev = vList;
return(pList);
/* si on n'a pas trouve l'element precedent */
} else {
if(pList == NULL)
{ /* si la liste est vide */
vList->data = data;
vList->prev = vList;
vList->next = vList;
return(vList);
} else {
/* c'est une insertion en queue d'une liste non vide */
vList->data = data;
vList->prev = pList->prev;
vList->next = pList;
vList->prev->next = vList;
pList->prev = vList;
return(pList);
}
}
}
/*********************************************************************/
/****************************************************************************/
/* Concatene la liste p2 a la liste p1 (p1 devant, p2 derriere) */
/* Renvoie la nouvelle liste cree. p1 et p2 sont consideres comme detruites */
List *list_concat(List *p1, List *p2)
{ List *vListPrev;
if(p1 == NULL) return(p2);
if(p2 == NULL) return(p1);
p1->prev->next = p2;
vListPrev = p1->prev;
p1->prev = p2->prev;
p2->prev->next = p1;
p2->prev = vListPrev;
return(p1);
}
/****************************************************************************/
/*****************************************************************/
/* Depile le dernier element de la liste pList. */
/* Le dernier est place dans data et est sorti de la liste */
/* list_pop renvoie le nouveau point d'entree de la liste pList. */
List *list_pop(List *pList, pointer *data)
{ List *vListPrev;
if(pList == NULL) { *data = NULL; return(NULL); }
/* si il n'y a que notre element dans la liste */
if(pList->next == pList)
{
*data = pList->data;
/* on libere l'element */
free(pList);
/* on renvoie une liste vide */
return(NULL);
} else {
*data = pList->prev->data;
vListPrev = pList->prev->prev;
vListPrev->next = pList;
free(pList->prev);
pList->prev = vListPrev;
return(pList);
}
}
/*****************************************************************/
/***********************************************************************/
/* Renvoie une copie de la liste pList. Les pointeurs data sont copies */
/* pas le contenu pointe. Il s'agit d'une liste avec des "alias" sur */
/* les elements de la premiere liste. */
List *list_copy(List *pList)
{ List *vListMove, *vCopy;
vCopy = list_new();
for(vListMove = pList;!list_is_end(pList,vListMove);list_move_next(pList,vListMove))
{
vCopy = list_append(vCopy, vListMove->data);
}
return(vCopy);
}
/***********************************************************************/
/**************************************************************************************/
/* Renvoie une copie de la liste pList. Les donnees contenu dans la liste sont copies */
/* avec la fonction copy_func. Elle recoit le pointeur de l'element d'origine et doit */
/* renvoyer un pointeur vers la copie. */
List *list_copy_full(List *pList, pointer (* copy_func)(pointer data))
{ List *vListMove, *vCopy;
vCopy = list_new();
for(vListMove = pList;!list_is_end(pList,vListMove);list_move_next(pList,vListMove))
{
vCopy = list_append(vCopy, copy_func(vListMove->data));
}
return(vCopy);
}
/**************************************************************************************/
/***********************************************************************/
/* Libere un element de la liste pList (pas la donnee pointe par data) */
/* Renvoie le nouveau point d'entree de la liste. */
List *list_free_chunk(List *pList, List *pToFree)
{ List *vListNext;
if(pList == NULL) return(NULL);
if(pToFree == NULL) return(pList);
/* si il n'y a que notre element dans la liste */
if(pToFree->next == pToFree)
{ /* on libere l'element */
free(pToFree);
/* on renvoie une liste vide */
return(NULL);
} else {
/* on recupere l'element qui suit celui que l'on veut supprimer */
vListNext = pToFree->next;
/* on chaine l'element precedent avec celui qui suit */
pToFree->prev->next = vListNext;
vListNext->prev = pToFree->prev;
/* on libere l'element a liberer */
free(pToFree);
if(pList == pToFree)
{
/* l'element a supprimer etait le premier, c'est */
/* donc le suivant qui devient le premier */
return(vListNext);
} else {
/* l'element a supprimer n'etait pas le premier. */
/* le premiere element de la liste ne change donc pas. */
return(pList);
}
}
}
/***********************************************************************/
/***************************************************************/
/* Trie la liste pList. La fonction cmp_func est utilise pour */
/* determine l'ordre. Elle doit renvoyer 0 si p1 pointe sur un */
/* element equivalent a p2. < 0 si p1 est inferieur a p2, >0 */
/* si p2 est superieur a p1. */
/* Renvoie la liste triee. */
List *list_sort(List *pList,int (* cmp_func)(pointer p1, pointer p2))
{ List *vListMove;
List *vListSmallest;
List *vListRes;
vListRes = list_new();
/* l'algorithme de trie utilise est le trie par selection */
/* cela consiste a chercher le plus petit element le sortir de */
/* la liste pList et le rajouter a la fin de la liste vListRes */
/* et de repeter cela jusqu'a ce qu'il n'y ai plus rien dans pList */
while(!list_is_empty(pList))
{
for(vListMove = list_next(pList,pList), vListSmallest = pList;
!list_is_end(pList,vListMove); list_move_next(pList,vListMove))
{
if(cmp_func(list_data(vListMove),list_data(vListSmallest)) < 0)
{ vListSmallest = vListMove; }
}
vListRes = list_append(vListRes,list_data(vListSmallest));
pList = list_free_chunk(pList, vListSmallest);
}
return(vListRes);
}
/***************************************************************/
/*************************************************************/
/* Insere l'element data dans la liste pList de maniere trie */
/* d'apres la fonction cmp_func. Elle doit renvoyer 0 si p1 */
/* pointe sur un element equivalent a p2. < 0 si p1 est */
/* inferieur a p2, >0 si p2 est superieur a p1. */
/* Renvoie le nouveau point d'entree de la liste. */
List *list_insert_sorted(List *pList,int (* cmp_func)(pointer p1, pointer p2), pointer data)
{ List *vListMove, *vList;
/* on recherche le premier element superieur ou egale au nouveau */
for(vListMove = pList; !list_is_end(pList,vListMove) &&
(cmp_func(list_data(vListMove),data) < 0);
vListMove = list_move_next(pList,vListMove));
/* on alloue la memoire pour le nouvelle element */
if((vList = (List *)malloc(sizeof(List))) == NULL)
{ perror("malloc failed "); exit(1); }
if(list_is_empty(pList))
{ /* si la liste est vide */
vList->data = data;
vList->prev = vList;
vList->next = vList;
return(vList);
} else {
vList->data = data;
vList->prev = vListMove->prev;
vList->next = vListMove;
vListMove->prev = vList;
vList->prev->next = vList;
if(pList == vListMove)
return(vList);
else
return(pList);
}
}
/*************************************************************/
/***********************************************************/
/* Inverse l'ordre des elements de la liste pList */
/* Renvoie le nouveau point d'entree de la liste */
/* Cette operation peut ce faire pendant que l'on parcours */
/* (pas au sens multithreade du terme) */
/* la liste mais bien evidemment, le sens s'inverse. */
List *list_invert(List *pList)
{ List *vListMove, *vListMoveNext;
if(pList == NULL) return(NULL);
vListMove = pList;
do {
vListMoveNext = vListMove->next;
vListMove->next = vListMove->prev;
vListMove->prev = vListMoveNext;
vListMove = vListMoveNext;
} while(vListMove != pList);
/* pList est devenu le dernier element, donc le premier est celui qui suit */
return(pList->next);
}
/***********************************************************/
/*********************************************************************/
/* Recherche l'element de liste qui contient la premiere donnee data */
/* Renvoie l'element de liste si trouve, NULL sinon. */
List *list_find(List *pList, pointer data)
{ List *vListMove;
for(vListMove = pList; !list_is_end(pList,vListMove) && (list_data(vListMove) != data);
list_move_next(pList,vListMove));
return(vListMove);
}
/*********************************************************************/
/*********************************************************************************/
/* Recherche l'element de liste qui contient la premiere donnee pour laquelle la */
/* fonction find_func renvoie TRUE. La fonction find_func prend en parametre le */
/* pointeur contenu dans la liste et le pointeur your_data qui est donne par */
/* l'utilisateur (pour y stocker ce dont il a besoin pour la comparaison). */
/* Renvoie l'element de liste si trouve, NULL sinon. */
List *list_find_full(List *pList, pointer your_data,
boolean (* find_func)(pointer data, pointer your_data))
{ List *vListMove;
for(vListMove = pList;
!list_is_end(pList,vListMove) && !find_func(list_data(vListMove),your_data);
list_move_next(pList,vListMove));
return(vListMove);
}
/*********************************************************************************/