commit 6fe492faf6cd397b06f01c2c9305e310c88ee290 Author: smas Date: Tue Jul 18 14:51:56 2000 +0000 First stable version LINUX / SOLARIS compatible. diff --git a/doc/libnode.doc b/doc/libnode.doc new file mode 100644 index 0000000..92a1947 Binary files /dev/null and b/doc/libnode.doc differ diff --git a/doc/man3/libnode.3 b/doc/man3/libnode.3 new file mode 100644 index 0000000..90903d1 --- /dev/null +++ b/doc/man3/libnode.3 @@ -0,0 +1,947 @@ +'\" t +.\" @(#)LIBNODE.3 1.0 99/10/12 SMA; +.TH LIBNODE 3 "10 Oct 1999" +.SH NOM +LIBNODE (librairie de structure de donnees a base de noeuds) +.SH SYNOPSIS +.LP +.B cc [flag ...] file ... -lver -ldl -lnode [library ...] +.LP +.B #include +.LP +.BI "NDT_Status ND_Library_Open ( int " Debug_Mode " );" +.LP +.BI "NDT_Status ND_Library_Close ( void );" +.LP +.BI "NDT_Status ND_Library_Stderr_Set ( FILE * " Out " );" +.LP +.BI "NDT_Status ND_DataStruct_Open ( NDT_Root ** " Root ", NDT_DataStruct_Type " Type ", const char * " Allocator ", const char * " Desallocator ", void * " User " );" +.LP +.BI "NDT_Status ND_DataStruct_Close ( NDT_Root * " Root " );" +.LP +.BI "NDT_Status ND_DataStruct_Reorg ( NDT_Root * " Root " );" +.LP +.BI "NDT_Status ND_DataStruct_Traverse ( NDT_Root * " Root ", NDT_Command, void * " Command ", void * " Data " );" +.LP +.BI "NDT_Status ND_DataStruct_Convert ( NDT_Root * " Root ", ND_Conversion_Type " Target_Type " );" +.LP +.BI "NDT_Status ND_DataStruct_Info_Print ( NDT_Root * " Root ", FILE * " Out " );" +.LP +.BI "NDT_Status ND_DataStruct_Print ( NDT_Root * " Root ", FILE * " Out " );" +.LP +.BI "NDT_Status ND_DataStruct_Check ( NDT_Root * " Root ", int * " Nb_Detected ", int * " Nb_Corrected " ,FILE * " Out " );" +.LP +.BI "NDT_Status ND_DataStruct_Dump ( NDT_Root * " Root ", FILE * " Out " );" +.LP +.BI "NDT_Status ND_Node_Root_Get ( NDT_Root ** " Root ", NDT_Node * " Node " );" +.LP +.BI "NDT_Status ND_Node_First_Get ( NDT_Root * " Root ", NDT_Node ** " Node " );" +.LP +.BI "NDT_Status ND_Node_Last_Get ( NDT_Root * " Root ", NDT_Node ** " Node " );" +.LP +.BI "NDT_Status ND_Node_Next_Get ( NDT_Node * " Node ", NDT_Node ** " Next_Node " );" +.LP +.BI "NDT_Status ND_Node_Previous_Get ( NDT_Node * " Node ", NDT_Node ** " Prev_Node " );" +.LP +.BI "NDT_Status ND_Node_Add ( NDT_Root * " Root ", NDT_Node * " Node " );" +.LP +.BI "NDT_Status ND_Node_Remove ( NDT_Node * " Node " );" +.LP +.BI "NDT_Status ND_Node_Find ( NDT_Root * " Root ", NDT_Node ** " Node ",void * " Value " , void * " Data " );" +.LP +.BI "NDT_Status ND_Value_Alloc ( NDT_Root * " Root ", void ** " Value ", ... );" +.LP +.BI "NDT_Status ND_Value_Add ( NDT_Root * " Root ", void * " Value " );" +.LP +.BI "NDT_Status ND_Value_Remove ( NDT_Root * " Root ", void * " Reference_Value " , void ** " Removed_Value " );" +.LP +.BI "NDT_Status ND_Value_Free ( NDT_Root * " Root ", void * " Value " );" +.LP +.BI "NDT_Status ND_Manager_Exec (const char * " Function_Name ", ...)" +.LP +.BI "NDT_Status ND_Allocator_Exec (const char * " Function_Name ", void ** " Ptr ", size_t " Size ", void * " Data " );" +.LP +.BI "NDT_Status ND_Desallocator_Exec (const char * " Function_Name ", void * " Ptr ", void * " Data " );" +.LP +.SH DESCRIPTION +.LP +La bibliotheque LIBNODE implemente deux types de structure de donnees a base de noeuds : +.LP +.RS 3 +- liste chainee +.LP +- arbre binaire +.RS -3 +.LP +Une structure de donnees est composee d'une racine ( voir le type +.B NDT_Root +) et de zero, un ou plusieurs noeuds (voir le type +.B NDT_Node +). +.LP +Fondamentalement, seul le chainage entre les noeuds distingue les differents types de structure implementes dans cette librairie. +.LP +La librairie LIBNODE implemente les fonctions minimales pour ce type de structure. +Elle pourra bien entendu etre enrichie suite aux remarques des utilisateurs. +.LP +.SH TYPES +.LP +La librairie LIBNODE definit les types suivants : +.LP +.BI NDT_Root +.LP +.RS 3 +Designe le type d'une racine de structure de donnees +.LP +Il s'agit d'une structure qui contient toutes les informations statistiques de la structure de donnees sous-jacente : +.LP +.RS 3 +- nombre de noeuds ( +.B ND_Node_Number +) +.LP +- profondeur minimum ( +.B Min_Depth +) (pour les arbres) +.LP +- profondeur maximum ( +.B Max_Depth +) (pour les arbres) +.LP +- nombre de reequilibrages ( +.B Nb_Equ +) (pour les arbres) +.RS -3 +.LP +La structure racine pointe sur les noeuds de tete ( +.B Head +) et de queue ( +.B Queue +) de la structure de donnees. +Pour une liste chainee, le noeud de tete est le premier noeud de la liste et le noeud de queue est le dernier noeud de la liste. +Pour un arbre binaire, le noeud de tete et le noeud de queue correpondent tous deux au meme noeud racine de l'arbre. +.LP +La gestion des arbres binaires prend en compte un reequilibrage automatique. +La structure racine conserve pour cela la taille de la plus grande branche de l'arbre ( +.B Max_Depth +) ainsi que celle de la plus courte ( +.B Min_Depth +). +Pour un arbre auto-equilibre, le depassement d'un seuil ( +.B Max_Dif +) provoque immediatement son reequilibrage. +.LP +La racine d'une structure reference enfin les fonctions suivantes par leur nom : +.LP +.RS 3 +- +.B Manager +: fonction qui implemente les commandes specifiques a realiser sur les valeurs, notamment : +.RS 3 +.LP +- la creation d'une valeur +.LP +- la suppression d'une valeur +.LP +- l'affichage d'une valeur +.LP +- la comparaison de deux valeurs +.RS -3 +.LP +- +.B Allocator +: fonction qui realise l'allocation de memoire pour la structure +.LP +- +.B Desallocator +: fonction qui realise la desallocation de memoire pour la structure +.LP +.RS -3 +.I NB +: une racine contient un pointeur librement utilisable par l'utilisateur ( +.B User +). +.LP +.RS -3 +.B NDT_DataStruct_Type +.LP +.RS 3 +Ce type definit sur un entier long le type de chainage de la structure de donnees : +.LP +.RS 3 +- +.B NDD_DS_LIST +: liste chainee +.LP +- +.B NDD_DS_TREE +: arbre binaire +.RS -3 +.LP +et son mode de gestion : +.RS 3 +.LP +- +.B NDD_MN_FIFO +(ou +.B NDD_MN_LILO +) : principe de la file d'attente (First In First Out) +.LP +- +.B NDD_MN_FILO +(ou +.B NDD_MN_LIFO +) : principe de la pile (First In Last Out) +.LP +- +.B NDD_MN_ORDERED +: ordonnancement des valeurs (liste triee). +Losque deux noeuds ont la meme valeur, ils seront ordonnes dans l'ordre chronologique d'insertion. +.LP +Toutefois, l'utilisateur pourra combiner par addition binaire les types +.B NDD_MN_ORDERED +et +.B NDD_MN_FILO +afin que deux noeuds de meme valeur soient ordonnes dans l'ordre inverse. +.LP +- +.B NDD_MN_AUTO_EQU +: auto-equilibre (arbre) +.RS -3 +.LP +Les valeurs NDD_DS* et NDD_MN* peuvent etre utilisees de maniere combinee par addition binaire. +.LP +.I Exemple +: +.LP +Mon_Type = +.B NDD_DS_LIST +| +.B NDD_MN_ORDERED +; +.LP +Mon_Type = +.B NDD_DS_TREE +| +.B NDD_MN_AUTO_EQU +; +.LP +Des valeurs "masque" permettent de ne recuperer que l'une des deux parties du type : +.LP +.RS 3 +- +.B NDD_DS_MSK +: masque sur le type de chainage +.LP +- +.B NDD_MN_MSK +: masque sur le mode de gestion +.LP +.RS -3 +.I Exemple +: +.LP +(Mon_Type & +.B NDD_DS_MSK +) renverra la valeur +.B NDD_DS_LIST +ou +.B NDD_DS_TREE +. +.LP +(Mon_Type & +.B NDD_MN_MSK +) renverra l'une des valeurs +.B NDD_MN_FILO +, +.B NDD_MN_FIFO +, +.B NDD_MN_ORDERED +ou +.B NDD_MN_AUTO_EQU +. +.LP +.RS -3 +.BI NDT_Node +.LP +.RS 3 +Designe le type d'un noeud +.LP +Il s'agit d'une structure qui permet aux noeuds d'etre relies les uns aux autres : +.LP +.RS 3 +- pointeur sur le noeud droite ( +.B Right +) +.LP +- pointeur sur le noeud gauche ( +.B Left +) +.RS -3 +.LP +Pour une structure de type arbre, chaque noeud pointe aussi sur son noeud pere ( +.B Parent +). +Chaque noeud possede enfin un pointeur sur sa structure racine ( +.B Root +). +.LP +A chaque noeud sera associee une valeur dont l'utilisateur de la librairie devra lui meme definir le type. +.RS -3 +.LP +.BI NDT_Value +.LP +.RS 3 +Designe le type d'une valeur attachee a un noeud. Ce type sera surcharge par celui defini par l'utilisateur. +.LP +.RS -3 +.BI NDT_Manager +.LP +.RS 3 +Designe le type d'une fonction manager. +.LP +Une fonction manager est attachee a la racine de la structure via son nom et permet d'executer des commandes (voir +.B NDT_Command +) specifiques sur la structure ou sur ses valeurs. +.LP +L'implementation des ces commandes est a definir par l'utilisateur lui-meme. +.LP +Le premier argument d'une fonction manager correspond toujours au type de la commande a executer. +.LP +Les autres arguments dependent bien evidemment de la commande a executer. +.LP +Une fonction manager doit etre executee via la fonction +.B NDT_Manager_Exec +(voir FONCTIONS). +.LP +.RS -3 +.BI NDT_Command +.LP +.RS 3 +Designe le type d'une commande pouvant etre executee par le manager : +.RS 3 +.LP +- +.B NDD_CMD_COMP_VALUE +: comparaison de valeurs +.LP +- +.B NDD_CMD_MAKE_VALUE +: creation de valeur +.LP +- +.B NDD_CMD_PRINT_VALUE +: affichage de valeur +.LP +- +.B NDD_CMD_DELETE_VALUE +: suppression de valeur +.LP +- +.B NDD_CMD_PRINT_INFO +: affichage des informations de la racine +.RS -3 +.LP +.I NB +Toutes ces commandes ne doivent pas necessairement etre implementees par l'utilisateur. A priori, seule la commande permettant de detruire une valeur est obligatoire. +De nouvelles commandes pourront aussi etre definies par l'utilisateur, sous reserve qu'elles soient implementee par la fonction manager. +.RS -3 +.LP +.BI NDT_Allocator +.LP +.RS 3 +Designe le type d'une fonction d'allocation memoire. +.LP +Une fonction d'allocation est attachee a la racine de la structure par son nom et permet de d'allouer de la memoire pour le stockage de la structure (racine et noeuds). +.LP +Par defaut, une structure de donnees definira la fonction malloc() comme fonction d'allocation. +.LP +.I NB +: une fonction d'allocation devra etre executee via la fonction +.B NDT_Allocator_Exec +(voir FONCTIONS). +.LP +.RS -3 +.BI NDT_Desallocator +.LP +.RS 3 +Designe le type d'une fonction de desallocation memoire. +.LP +Une fonction de desallocation est attachee a la racine de la structure par son nom et permet de liberer la memoire allouee pour le stockage de la structure. +.LP +Par defaut, une structure de donnees definira la fonction free() comme fonction de desallocation. +.LP +.I NB +: une fonction de desallocation devra etre executee via la fonction +.B NDT_Desallocator_Exec +(voir FONCTIONS). +.LP +.RS -3 +.SH FONCTIONS +.BI "ND_Library_Open ( int " Debug_Mode " )" +.RS 3 +.LP +Cette fonction permet d'initialiser les eventuelles ressources de la librairie. +Elle doit etre systematiquement appelee au debut de chaque programme utilisant la librairie. +.LP +L'argument +.I Debug_Mode +(TRUE ou FALSE) permet d'utiliser la librairie en mode bavard ou non, ce qui sigifie que tous les messages d'erreur seront affiches par defaut sur la sortie standard. +.LP +.RS -3 +.BI "ND_Library_Close ( void )" +.RS 3 +.LP +Cette fonction permet de fermer les eventuelles ressources de la librairie. +Elle doit etre systematiquement appelee a la fin de chaque programme utilisant la librairie. +.LP +.RS -3 +.BI "NDT_Status ND_Library_Stderr_Set ( FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet de definir +.I Out +comme la sortie standard des messages d'erreur de la librarie. +.RS -3 +.LP +.BI "NDT_Status ND_DataStruct_Open ( NDT_Root ** " Root ", NDT_DataStruct_Type " Type ", const char * " Allocator ", const char * " Desallocator ", void * " User " , int " Own_Value " );" +.RS 3 +.LP +Cette fonction permet de creer une structure de donnees. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (Out) +.I Root +: l'adresse du pointeur sur la racine de la nouvelle structure de donnees +.LP +* (In) +.I Type +: le type de la nouvelle structure de donnees +.LP +* (In) +.I Allocator +: le nom de la fonction d'allocation memoire (fonction de type +.B NDT_Allocator +) associee a la nouvelle structure de donnees. +Si cet argument est positionne a NULL, alors la fonction d'allocation locale malloc() sera utilisee par defaut. +.LP +* (In) +.I Desallocator +: le nom de la fonction de desallocation memoire (fonction de type +.B NDT_Desallocator +) associee a la nouvelle structure de donnees. +Si cet argument est positionne a NULL, alors la fonction de desallocation locale free() sera utilisee par defaut. +.LP +* (In) +.I User +: un pointeur de donnees qui sera systematiquement passe au manager pour l'allocation et la desallocation. +.LP +* (In) +.I Own_Value +: valeur TRUE ou FALSE indiquant si la structure est proprietaire de ses valeurs. +.LP +.I NB +: si une structure est proprietaire de ses valeurs, alors sa destruction provoque aussi la desallocation des valeurs rattachees a ses noeuds +.LP +.RS -3 +.RS -3 +.BI "NDT_Status ND_DataStruct_Close ( NDT_Root * " Root " );" +.RS 3 +.LP +Cette fonction permet de detruire une structure de donnees (desallocation des ressources). +.LP +L'argument +.I Root +est un pointeur sur la racine de la structure de donnees a detruire. +.LP +.I NB +: les valeurs de la structure seront desallouees en meme temps que leur noeud selon que la structure est proprietaire ou non de ses valeurs. +.LP +.RS -3 +.BI "NDT_Status ND_DataStruct_Reorg ( NDT_Root * " Root " );" +.RS 3 +.LP +Cette fonction permet de reorganiser les donnees d'une structure (tri pour une liste, reequilibrage pour un arbre). +.LP +L'argument +.I Root +est un pointeur sur la racine de la structure de donnees a reorganiser. +.LP +.RS -3 +.BI "NDT_Status ND_DataStruct_Traverse ( NDT_Root * " Root ", NDT_Command, void * " Command ", void * " Data " );" +.RS 3 +.LP +Cette fonction permet de parcourir tous les noeuds d'une structure de donnees avec execution d'une commande sur chacun d'eux. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees a parcourir. +.LP +* (In) +.I Command +: la commande a executer sur chaque noeud traverse +.LP +* (In) +.I Data +: un pointeur de donnees propre a la commande +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_DataStruct_Convert ( NDT_Root * " Root ", ND_Conversion_Type " Target_Type " );" +.RS 3 +.LP +Cette fonction permet de convertir une structure de donnees d'un type en un autre. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees a convertir. +.LP +* (In) +.I Target_Type +: le type cible de la structure +.LP +.RS -3 +.RS -3 +.BI "NDT_Status ND_DataStruct_Print ( NDT_Root * " Root ", FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet d'afficher toutes les valeurs des noeuds d'une structure de donnees. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees a afficher. +.LP +* (In) +.I Out +: un pointeur sur le flux de sortie +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_DataStruct_Info_Print ( NDT_Root * " Root ", FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet d'afficher des informations concernant une structure de donnees. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (In) +.I Out +: un pointeur sur le flux de sortie +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_DataStruct_Check ( NDT_Root * " Root ", int * " Nb_Detected ", int * " Nb_Corrected " ,FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet de verifier et de corriger des incoherences contenues dans une structure de donnees. +Elle verifie notamment les liens entre les noeuds, supprime les noeuds sans valeur ou ceux dont les valeurs ne sont pas accessibles et met a jour les informations statistiques de la racine. +Un rapport de toutes les erreurs detectees ou corrigees est affiche. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees a verifier. +.LP +* (Out) +.I Nb_Detected +: un pointeur sur le nombre d'erreurs detectees +.LP +* (Out) +.I Nb_Corrected +: un pointeur sur le nombre d'erreurs corrigees +.LP +* (In) +.I Out +: un pointeur sur le flux de sortie du rapport +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_DataStruct_Dump ( NDT_Root * " Root ", FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet d'afficher toutes les informations de la structure (racine et contenu). +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees a afficher. +.LP +* (In) +.I Out +: un pointeur sur le flux de sortie +.RS -3 +.LP +.I NB +: cette fonction a ete implementee dans une optique de deboggage. +.LP +.RS -3 +.BI "NDT_Status ND_Node_Root_Get ( NDT_Root ** " Root ", NDT_Node * " Node " );" +.LP +.RS 3 +Cette fonction permet de recuperer la racine d'une structure a partir d'un de ses noeuds. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (Out) +.I Root +: l'adresse d'un pointeur sur la racine a recuperer +.LP +* (In) +.I Node +: un pointeur sur un noeud +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Node_First_Get ( NDT_Root * " Root ", NDT_Node ** " Node " );" +.LP +.RS 3 +Cette fonction permet de recuperer le premier noeud d'une structure. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure +.LP +* (Out) +.I Node +: l'adresse d'un pointeur sur le premier noeud a recuperer +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Node_Last_Get ( NDT_Root * " Root ", NDT_Node ** " Node " );" +.LP +.RS 3 +Cette fonction permet de recuperer le dernier noeud d'une structure. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure +.LP +* (Out) +.I Node +: un pointeur sur le dernier noeud a recuperer +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Node_Next_Get ( NDT_Node * " Node ", NDT_Node ** " Next_Node " );" +.LP +.RS 3 +Cette fonction permet de recuperer le noeud qui suit immediatement un noeud particulier. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Node +: un pointeur sur le noeud de reference +.LP +* (Out) +.I Next_Node +: l'adresse d'un pointeur sur le noeud qui suit le noeud de reference +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Node_Previous_Get ( NDT_Node * " Node ", NDT_Node ** " Prev_Node " );" +.LP +.RS 3 +Cette fonction permet de recuperer le noeud qui precede immediatement un noeud particulier. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Node +: un pointeur sur le noeud de reference +.LP +* (Out) +.I Prev_Node +: l'adresse d'un pointeur sur le noeud qui precede le noeud de reference +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Node_Add ( NDT_Root * " Root ", NDT_Node * " Node " );" +.LP +.RS 3 +Cette fonction permet d'ajouter un noeud a une structure. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (In) +.I Node +: un pointeur sur le noeud a ajouter +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Node_Remove ( NDT_Node * " Node " );" +.RS 3 +.LP +Cette fonction permet de supprimer le noeud d'une structure de donnees. +.LP +L'argument +.I Node +est un pointeur sur le noeud a supprimer +.LP +.I NB +: le noeud supprime n'est pas detruit mais simplement detache de la structure +.LP +.RS -3 +.BI "NDT_Status ND_Node_Find ( NDT_Root * " Root ", NDT_Node ** " Node ", void * " Value " , void * " Data " );" +.LP +.RS 3 +Cette fonction permet de rechercher dans une structure de donnees le premier noeud correspondant a une valeur. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (Out) +.I Node +: l'adresse d'un pointeur sur le noeud resultat +.LP +* (In) +.I Value +: un pointeur sur la valeur a rechercher +.LP +* (In) +.I Data +: un pointeur de donnees qui sera passe a la fonction manager pour la recherche +.RS -3 +.LP +.RS -3 +.LP +.BI "NDT_Status ND_Value_Alloc ( NDT_Root * " Root ", void ** " Value ", ... );" +.LP +.RS 3 +Cette fonction permet d'allouer une valeur pour une structure de donnees. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (Out) +.I Value +: l'adresse d'un pointeur sur la valeur a allouer +.LP +* (In) +.I ... +: des arguments supplementaires pour l'allocation de la valeur +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Value_Add ( NDT_Root * " Root ", void * " Value " );" +.LP +.RS 3 +Cette fonction permet d'ajouter une valeur a une structure de donnees. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (In) +.I Value +: un pointeur sur la valeur a ajouter +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Value_Remove ( NDT_Root * " Root ", void * " Reference_Value " , void ** " Removed_Value " );" +.RS 3 +.LP +Cette fonction permet de supprimer le premier noeud correspondant a une valeur. +.LP +Elle doit recevoir les arguments suivants : +.RS 3 +.LP +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (In) +.I Reference_Value +: un pointeur sur la valeur de reference +.LP +* (Out) +.I Removed_Value +: l'adresse d'un pointeur sur la valeur du noeud supprime +.LP +.RS -3 +.I NB +: la suppression d'un noeud implique son retrait de la structure et sa desallocation. +.LP +Si la structure contient plusieurs fois la valeur, seul le premier noeud correspondant a cette valeur est detruit. +.LP +.RS -3 +.BI "NDT_Status ND_Value_Free ( NDT_Root * " Root ", void * " Value " );" +.LP +.RS 3 +Cette fonction permet de desallouer une valeur faisant partie d'une structure de donnees. +.LP +Elle doit recevoir les arguments suivants : +.LP +.RS 3 +* (In) +.I Root +: un pointeur sur la racine de la structure de donnees +.LP +* (In) +.I Value +: un pointeur sur la valeur a desallouer +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Manager_Exec (const char * " Function_Name ", ...)" +.LP +.RS 3 +Cette fonction permet d'executer une fonction manager a partir de son nom. +.LP +L'argument +.I Function_Name +est le nom de la fonction manager (fonction de type +.B NDT_Manager +), suivi de tous les arguments contextuels necessaires a son execution. +.LP +.RS -3 +.BI "NDT_Status ND_Allocator_Exec (const char * " Function_Name ", void ** " Ptr ", size_t " Size ", void * " Data " );" +.LP +.RS 3 +Cette fonction permet d'executer une fonction d'allocation a partir de son nom. +.LP +Elle doit recevoir les arguments suivants : +.RS 3 +.LP +* (In) +.I Function_Name +: le nom de la fonction d'allocation (fonction de type +.B NDT_Allocator +) +.LP +* (Out) +.I Ptr +: l'adresse d'un pointeur sur la zone a allouer +.LP +* (In) +.I Size +: la taille a allouer +.LP +* (In) +.I Data +: un pointeur de donneees utile a la fonction d'allocation +.RS -3 +.LP +.RS -3 +.BI "NDT_Status ND_Desallocator_Exec (const char * " Function_Name ", void * " Ptr ", void * " Data " );" +.LP +.RS 3 +Cette fonction permet d'executer une fonction de desallocation a partir de son nom. +.LP +Elle doit recevoir les arguments suivants : +.RS 3 +.LP +* (In) +.I Function_Name +: le nom de la fonction de desallocation (fonction de type +.B NDT_Desallocator +) +.LP +* (In) +.I Ptr +: l'adresse de la zone memoire a desallouer +.LP +* (In) +.I Data +: un pointeur de donneees utile a la fonction de desallocation +.RS -3 +.LP +.RS -3 +.SH CODES RETOUR +.LP +Toutes les fonctions constituant l'API de la librairie LIBND retournent un code de type +.B NDT_Status +: +.LP +.RS 3 +- +.B NDS_OK +: la fonction s'est correctement executee et a produit un resultat +.LP +- +.B NDS_KO +: la fonction s'est correctement executee mais n'a pas produit de resultat +.LP +- +.B NDS_ERRAPI +: la fonction a ete appelee avec des arguments de valeur incorrecte +.LP +- +.B NDS_ERRMEM +: la fonction ne s'est pas correctement executee pour un probleme d'allocation memoire +.RS -3 +.LP +La macro +.B ND_ERROR(rc) +permet de tester si un code retour correspond a une erreur. +.LP +En cas d'erreur, la variable ND_Error_Msg contient un message du type : +.LP +.RS 3 +Error : +.RS -3 +.LP +Lorsque le manager est appele avec la commande +.B NDD_CMD_COMP_VALUE +(comparaison de valeurs), l'une des trois valeurs suivantes est retournee : +.RS 3 +.LP +- +.B NDS_EQUAL +.LP +- +.B NDS_LOWER +.LP +- +.B NDS_GREATER +.LP +.RS -3 +.LP +.SH VOIR AUSSI +.B libdatastr +(3) diff --git a/include/node.h b/include/node.h new file mode 100644 index 0000000..3024022 --- /dev/null +++ b/include/node.h @@ -0,0 +1,461 @@ +#ifndef _LIBNODE +#define _LIBNODE + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* + Différence de profondeur entre la branche la plus courte et + la plus longue d'un arbre. + Le dépassement de ce seuil provoque le rééquilibrage de l'arbre +*/ + +#define DEF_MAX_DIF 100 + +/* Types de structure */ + +typedef int NDT_DataStruct_Type; + +#define NDD_DS_LIST 0001 /* liste chaînée */ +#define NDD_DS_TREE 0002 /* arbre binaire */ +#define NDD_DS_MSK (NDD_DS_LIST | NDD_DS_TREE) + +#define ND_IS_LIST(r) ((r)->Type & NDD_DS_LIST) +#define ND_IS_TREE(r) ((r)->Type & NDD_DS_TREE) + +#define NDD_MN_FIFO 0010 /* principe de la file d'attente (First In First Out) */ +#define NDD_MN_LILO NDD_MN_FIFO +#define NDD_MN_FILO 0020 /* principe de la pile (First In Last Out) */ +#define NDD_MN_LIFO NDD_MN_FILO +#define NDD_MN_ORDERED 0040 /* liste triée */ +#define NDD_MN_AUTO_EQU 0100 /* arbre auto-équilibré */ +#define NDD_MN_MSK (NDD_MN_FIFO | NDD_MN_FILO | NDD_MN_ORDERED | NDD_MN_AUTO_EQU) + +#define ND_IS_FIFO(r) ((r)->Type & NDD_MN_FIFO) +#define ND_IS_FILO(r) ((r)->Type & NDD_MN_FILO) +#define ND_IS_ORDERED(r) ((r)->Type & NDD_MN_ORDERED) +#define ND_IS_AUTO_EQU(r) ((r)->Type & NDD_MN_AUTO_EQU) + +/* Commandes du manager */ + +typedef int NDT_Command; + +#define NDD_CMD_MAKE_VALUE 1 +#define NDD_CMD_COMP_VALUE 2 +#define NDD_CMD_SUM_VALUES 3 +#define NDD_CMD_PRINT_VALUE 4 +#define NDD_CMD_DELETE_VALUE 5 +#define NDD_CMD_PRINT_INFO 6 + +/* Types de réponse du manager ou code retour des diverses fonctions */ + +typedef int NDT_Status; + +#define ND_ERROR(s) ((s) < 0) /* Tous les codes retour négatifs correspondent à des erreurs */ + +#define NDS_OK 1 +#define NDS_KO 0 + +#define NDS_YES 1 +#define NDS_NO 0 + +#define NDS_EQUAL 1 +#define NDS_GREATER 2 +#define NDS_LOWER 3 + +#define NDS_ERRMEM -1 /* Problème d'allocation mémoire */ +#define NDS_ERRAPI -2 /* Utilisation incorrecte des API */ + +/* Pointeur de fonction sur le manager */ + +typedef NDT_Status NDT_Manager (va_list); + +/* Pointeur de fonction sur l'allocateur */ + +typedef NDT_Status NDT_Allocator (size_t, void **, void *); + +/* Pointeur de fonction sur le désallocateur */ + +typedef NDT_Status NDT_Desallocator (void *, void *); + +/* Structure racine */ + +typedef struct NDT_Root { + NDT_DataStruct_Type Type; /* Type de la structure (liste, arbre ... ) */ + long Node_Number; /* Nombre de noeuds dans la structure */ + long Min_Depth; /* Profondeur minimale de l'arbre */ + long Max_Depth; /* Profondeur maximale de l'arbre */ + long Max_Dif; /* Différence maximale autorisée entre la branche la plus courte et la plus longue */ + long Nb_Equ; /* Nombre de réquilibrages réalisés sur l'arbre */ + char Manager [50]; /* Nom de la fonction manager */ + char Allocator [50]; /* Nom de la fonction d'allocation */ + char Desallocator [50]; /* Nom de la fonction de désallocation */ + struct NDT_Node * Head; /* Noeud de tête */ + struct NDT_Node * Queue; /* Noeud de queue */ + struct NDT_Node * Save; /* Pointeur de sauvegarde (utile pour la fonction de restauration) */ + void * User; /* Pointeur utilisable librement par l'utilisateur */ + short int Own_Value; /* Indique si la structure est propriétaire de ses valeurs */ +} NDT_Root; + +/* Structure de noeud */ + +typedef struct NDT_Node { + struct NDT_Root * Root; + struct NDT_Node * Parent; + struct NDT_Node * Left; + struct NDT_Node * Right; + void * Value; +} NDT_Node; + +char ND_Error_Msg [512]; + +/* Définition des alias de l'API */ + +#ifndef ND_MODE +#define ND_MODE 0 +#endif + +#if ND_MODE == 1 /* API sans vérification des arguments */ + +#define ND_Library_Open ND_Library_Open_I +#define ND_Library_Close ND_Library_Close_I +#define ND_Library_Stderr_Set ND_Library_Stderr_Set_I +#define ND_DataStruct_Open ND_DataStruct_Open_I +#define ND_DataStruct_Close ND_DataStruct_Close_I +#define ND_DataStruct_Reorg ND_DataStruct_Reorg_I +#define ND_DataStruct_Traverse ND_DataStruct_Traverse_I +#define ND_DataStruct_Convert ND_DataStruct_Convert_I +#define ND_DataStruct_Info_Print ND_DataStruct_Info_Print_I +#define ND_DataStruct_Print ND_DataStruct_Print_I +#define ND_DataStruct_Check ND_DataStruct_Check_I +#define ND_DataStruct_Dump ND_DataStruct_Dump_I +#define ND_Node_Root_Get ND_Node_Root_Get_I +#define ND_Node_First_Get ND_Node_First_Get_I +#define ND_Node_Last_Get ND_Node_Last_Get_I +#define ND_Node_Next_Get ND_Node_Next_Get_I +#define ND_Node_Previous_Get ND_Node_Previous_Get_I +#define ND_Node_Add ND_Node_Add_I +#define ND_Node_Remove ND_Node_Remove_I +#define ND_Node_Find ND_Node_Find_I +#define ND_Value_Alloc ND_Value_Alloc_I +#define ND_Value_Add ND_Value_Add_I +#define ND_Value_Remove ND_Value_Remove_I +#define ND_Value_Free ND_Value_Free_I +#define ND_Manager_Exec ND_Manager_Exec_I +#define ND_Allocator_Exec ND_Allocator_Exec_I +#define ND_Desallocator_Exec ND_Desallocator_Exec_I + +#else /* API avec vérification des arguments */ + +#define ND_Library_Open ND_Library_Open_C +#define ND_Library_Close ND_Library_Close_C +#define ND_Library_Stderr_Set ND_Library_Stderr_Set_C +#define ND_DataStruct_Open ND_DataStruct_Open_C +#define ND_DataStruct_Close ND_DataStruct_Close_C +#define ND_DataStruct_Reorg ND_DataStruct_Reorg_C +#define ND_DataStruct_Traverse ND_DataStruct_Traverse_C +#define ND_DataStruct_Convert ND_DataStruct_Convert_C +#define ND_DataStruct_Info_Print ND_DataStruct_Info_Print_C +#define ND_DataStruct_Print ND_DataStruct_Print_C +#define ND_DataStruct_Check ND_DataStruct_Check_C +#define ND_DataStruct_Dump ND_DataStruct_Dump_C +#define ND_Node_Root_Get ND_Node_Root_Get_C +#define ND_Node_First_Get ND_Node_First_Get_C +#define ND_Node_Last_Get ND_Node_Last_Get_C +#define ND_Node_Next_Get ND_Node_Next_Get_C +#define ND_Node_Previous_Get ND_Node_Previous_Get_C +#define ND_Node_Add ND_Node_Add_C +#define ND_Node_Remove ND_Node_Remove_C +#define ND_Node_Find ND_Node_Find_C +#define ND_Value_Alloc ND_Value_Alloc_C +#define ND_Value_Add ND_Value_Add_C +#define ND_Value_Remove ND_Value_Remove_C +#define ND_Value_Free ND_Value_Free_C +#define ND_Manager_Exec ND_Manager_Exec_C +#define ND_Allocator_Exec ND_Allocator_Exec_C +#define ND_Desallocator_Exec ND_Desallocator_Exec_C + +#endif + +/*------------------------------------------------------------------------------*/ +/* Initialisation du contexte de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Open_I ( int Debug_Mode ); +NDT_Status ND_Library_Open_C ( int Debug_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Fermeture du contexte de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Close_I ( void ); +NDT_Status ND_Library_Close_C ( void ); + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Stderr_Set_I ( FILE * Out ); +NDT_Status ND_Library_Stderr_Set_C ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Création d'une nouvelle structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: adresse d'un pointeur sur la racine de la nouvelle structure */ +/* (I) Type: type de la structure.de données (liste ou arbre binaire) */ +/* (I) Allocator: pointeur vers la fonction d'allocation */ +/* (I) Desallocator: pointeur vers la fonction de désallocation */ +/* (I) Data : pointeur de données utiles à l'allocateur */ +/* (I) Own_Value : indique si la structure est propriétaire de ses valeurs */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Open_I ( NDT_Root ** Root, NDT_DataStruct_Type Type, \ + const char * Allocator, \ + const char * Desallocator, \ + void * Data, int Own_Value ); +NDT_Status ND_DataStruct_Open_C ( NDT_Root ** Root, NDT_DataStruct_Type Type, \ + const char * Allocator, \ + const char * Desallocator, \ + void * Data, int Own_Value ); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: pointeur sur la racine de la structure de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Close_I ( NDT_Root * Root ); +NDT_Status ND_DataStruct_Close_C ( NDT_Root * Root ); + +/*------------------------------------------------------------------------------*/ +/* Réorganisation d'une structure de données : */ +/* - ordonnancement d'une liste non ordonnée */ +/* - réquilibrage d'un arbre non auto-équilibré */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Reorg_I ( NDT_Root * Root ); +NDT_Status ND_DataStruct_Reorg_C ( NDT_Root * Root ); + +/*------------------------------------------------------------------------------*/ +/* Parcours de tous les noeuds d'une structure de données et exécution d'une */ +/* commande sur chacun d'eux */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Command: Commande à exécuter sur chaque noeud traversé */ +/* (I) Data: pointeur de données utilisateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Traverse_I ( NDT_Root * Root, NDT_Command Command, \ + void * Data ); +NDT_Status ND_DataStruct_Traverse_C ( NDT_Root * Root, NDT_Command Command, \ + void * Data ); + +/*------------------------------------------------------------------------------*/ +/* Conversion d'une structure de données d'un type en un autre */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Target_Type: type de structure cible */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Convert_I ( NDT_Root * Root, \ + NDT_DataStruct_Type Target_Type ); +NDT_Status ND_DataStruct_Convert_C ( NDT_Root * Root, \ + NDT_DataStruct_Type Target_Type ); + +/*------------------------------------------------------------------------------*/ +/* Affichage d'informations sur une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Info_Print_I ( NDT_Root * Root, FILE * Out ); +NDT_Status ND_DataStruct_Info_Print_C ( NDT_Root * Root, FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Affichage de la valeur de tous les noeuds d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Print_I ( NDT_Root * Root, FILE * Out ); +NDT_Status ND_DataStruct_Print_C ( NDT_Root * Root, FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Function de réparation d'une structure : */ +/* - vérifie que tous les noeuds sont correctement liés les uns aux autres */ +/* - corrige les informations statistiques de la racine */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (O) Nb_Detected : pointeur sur le nombre d'erreurs */ +/* (O) Nb_Corrected : pointeur sur le nombre d'erreurs */ +/* (I) Out : flux de sortie du rapport */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Check_I ( NDT_Root * Root, int * Nb_Detected, \ + int * Nb_Corrected, FILE * Out ); +NDT_Status ND_DataStruct_Check_C ( NDT_Root * Root, int * Nb_Detected, \ + int * Nb_Corrected, FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Affiche la structure de données et ses informations statistiques */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Dump_I ( NDT_Root * Root, FILE * Out ); +NDT_Status ND_DataStruct_Dump_C ( NDT_Root * Root, FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Récupération de la racine d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: Adresse du pointeur sur la racine à récupérer */ +/* (I) Node: pointeur sur le noeud dont on cherche la racine */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Root_Get_I ( NDT_Root ** Root, NDT_Node * Node ); +NDT_Status ND_Node_Root_Get_C ( NDT_Root ** Root, NDT_Node * Node ); + +/*------------------------------------------------------------------------------*/ +/* Récupération du premier noeud d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine dont on cherche le premier noeud */ +/* (O) Node : pointeur sur le noeud à récupérer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_First_Get_I ( NDT_Root * Root, NDT_Node ** Node ); +NDT_Status ND_Node_First_Get_C ( NDT_Root * Root, NDT_Node ** Node ); + +/*------------------------------------------------------------------------------*/ +/* Récupération du dernier noeud d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine dont on cherche le dernier noeud */ +/* (O) Node : pointeur sur le noeud à récupérer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Last_Get_I ( NDT_Root * Root, NDT_Node ** Node ); +NDT_Status ND_Node_Last_Get_C ( NDT_Root * Root, NDT_Node ** Node ); + +/*------------------------------------------------------------------------------*/ +/* Récupération du noeud suivant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node: pointeur sur le noeud dont on cherche le suivant */ +/* (O) Next_Node : pointeur sur le noeud suivant */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Next_Get_I ( NDT_Node * Node, NDT_Node ** Next_Node ); +NDT_Status ND_Node_Next_Get_C ( NDT_Node * Node, NDT_Node ** Next_Node ); + +/*------------------------------------------------------------------------------*/ +/* Récupération du noeud précédant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node: pointeur sur le noeud dont on cherche le précédant */ +/* (O) Prev_Node : pointeur sur le noeud précédant */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Previous_Get_I ( NDT_Node * Node, NDT_Node **Prev_Node ); +NDT_Status ND_Node_Previous_Get_C ( NDT_Node * Node, NDT_Node **Prev_Node ); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Node: pointeur sur le noeud à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Add_I ( NDT_Root * Root, NDT_Node * Node ); +NDT_Status ND_Node_Add_C ( NDT_Root * Root, NDT_Node * Node ); + +/*------------------------------------------------------------------------------*/ +/* Suppression d'un noeud dans une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Node: pointeur sur le noeud à supprimer de la structure de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Remove_I ( NDT_Node * Node); +NDT_Status ND_Node_Remove_C ( NDT_Node * Node); + +/*------------------------------------------------------------------------------*/ +/* Recherche un noeud à partir d'une valeur */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'abre */ +/* (O) Node : pointeur sur le noeud à récuperer */ +/* (I) Value : pointeur sur la valeur à rechercher */ +/* (I) Data : pointeur de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Find_I ( NDT_Root * Root, NDT_Node ** Node, void * Value, void * Data ); +NDT_Status ND_Node_Find_C ( NDT_Root * Root, NDT_Node ** Node, void * Value, void * Data ); + +/*------------------------------------------------------------------------------*/ +/* Allocation d'une valeur d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (O) Value : adresse d'un pointeur sur la valeur à allouer */ +/* (I) ... : arguments relatifs à l'allocation de la valeur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Alloc_I ( NDT_Root * Root, void ** Value, ... ); +NDT_Status ND_Value_Alloc_C ( NDT_Root * Root, void ** Value, ... ); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une valeur à une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Value: pointeur sur la valeur à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Add_I ( NDT_Root * Root, void * Value ); +NDT_Status ND_Value_Add_C ( NDT_Root * Root, void * Value ); + +/*------------------------------------------------------------------------------*/ +/* Suppression du premier noeud correspondant à une valeur donnée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Reference_Value : pointeur sur la valeur de référence */ +/* (I) Removed_Value : adresse d'un pointeur sur la valeur supprimée */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Remove_I ( NDT_Root * Root, void * Reference_Value, void ** Removed_Value ); +NDT_Status ND_Value_Remove_C ( NDT_Root * Root, void * Reference_Value, void ** Removed_Value ); + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'une valeur d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Value: pointeur sur la valeur à désallouer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Free_I ( NDT_Root * Root, void * Value ); +NDT_Status ND_Value_Free_C ( NDT_Root * Root, void * Value ); + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction Manager dont le nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction manager à exécuter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Manager_Exec_I ( const char * Function, ... ); +NDT_Status ND_Manager_Exec_C ( const char * Function, ... ); + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction d'allocation dont le nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction à exécuter */ +/* (O) Ptr : adresse d'un pointeur sur la zone à allouer */ +/* (I) Size : taille de la zone à allouer */ +/* (I) Data : pointeur de données utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Allocator_Exec_I ( const char * Function, void ** Ptr, \ + size_t Size, void * Data ); +NDT_Status ND_Allocator_Exec_C ( const char * Function, void ** Ptr, \ + size_t Size, void * Data ); + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction de désallocation le dont nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction à exécuter */ +/* (I) Ptr : adresse de la zone à désallouer */ +/* (I) Data : pointeur de données utiles au désallocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Desallocator_Exec_I ( const char * Function, void * Ptr, \ + void * Data ); +NDT_Status ND_Desallocator_Exec_C ( const char * Function, void * Ptr, \ + void * Data ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libnode.c b/lib/libnode.c new file mode 100644 index 0000000..2adfd7f --- /dev/null +++ b/lib/libnode.c @@ -0,0 +1,2674 @@ +#include + +VER_INFO_EXPORT (libnode,"$Revision: 1.1 $", "$Name: $",__FILE__,"$Author: smas $") + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* MODELE DE FONCTION MANAGER */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +NDT_Status Default_Manager ( va_list Args ) +{ + NDT_Command Command; + const char * Command_Name; + + Command = (NDT_Command) va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + /* + NDT_Root * Root = va_arg (Args, NDT_Root *); + void ** Value = va_arg (Args, void **); + va_list Value_Args = va_arg (Args, va_list); + ... = va_arg (Value_Args, ...); + */ + + Command_Name = "NDD_CMD_MAKE_VALUE"; + } + else if (Command == NDD_CMD_SUM_VALUES) + { + /* + void * Value = va_arg (Args, void *); + int * Total = va_arg (Args, int *); + */ + + Command_Name = "NDD_CMD_SUM_VALUES"; + } + else if (Command == NDD_CMD_COMP_VALUE) + { + /* + void * Value1 = va_arg (Args, void *); + void * Value2 = va_arg (Args, void *); + */ + + Command_Name = "NDD_CMD_COMP_VALUE"; + } + else if (Command == NDD_CMD_PRINT_VALUE) + { + /* + void * Value = va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + */ + + Command_Name = "NDD_CMD_PRINT_VALUE"; + } + else if (Command == NDD_CMD_DELETE_VALUE) + { + /* + void * Value = va_arg (Args, void *); + */ + + Command_Name = "NDD_CMD_DELETE_VALUE"; + } + else if (Command == NDD_CMD_PRINT_INFO) + { + /* + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + */ + + Command_Name = "NDD_CMD_PRINT_INFO"; + } + else + { + sprintf (ND_Error_Msg, "Calling default manager with an undefined command %d\n", Command); + ND_Error_Print (); + + return NDS_ERRAPI; + } + + sprintf (ND_Error_Msg, "Calling default manager with command %d (%s)\n", Command, Command_Name); + ND_Error_Print (); + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PUBLIQUES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS OPTIMISEES (ND_MODE = 1) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Initialisation du contexte de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Open_I ( int Debug_Mode ) +{ + if (Debug_Mode == TRUE) ND_Library_Stderr_Set_I (stderr); + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture du contexte de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Close_I ( void ) +{ + struct Symbol * Symbol, * Next_Symbol; + + /* Désallocation de la table des symboles locale */ + + Symbol = Symbol_Table; + + while (Symbol) + { + Next_Symbol = Symbol->Next; + free (Symbol->Name); + free (Symbol); + Symbol = Next_Symbol; + } + + Symbol_Table = NULL; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie de l'affichage des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Stderr_Set_I ( FILE * Out ) +{ + ND_stderr = Out; + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création d'une nouvelle structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: adresse d'un pointeur sur la racine de la nouvelle structure */ +/* (I) Type: type de la structure.de données (liste ou arbre binaire) */ +/* (I) Allocator: pointeur vers la fonction d'allocation */ +/* (I) Desallocator: pointeur vers la fonction de désallocation */ +/* (I) Data : pointeur de données utiles à l'allocateur */ +/* (I) Own_Value : indique si la structure est propriétaire de ses valeurs */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Open_I ( NDT_Root ** Root, NDT_DataStruct_Type Type, const char * Allocator, const char * Desallocator, void * Data, int Own_Value ) +{ + NDT_Status rc; + const char * Real_Allocator, * Real_Desallocator; + + /* Valeurs par défaut des fonctions d'allocation et de désallocation */ + + if (Allocator) Real_Allocator = Allocator; + else Real_Allocator = "ND_Malloc"; + + if (Desallocator) Real_Desallocator = Desallocator; + else Real_Desallocator = "ND_Free"; + + rc = ND_Root_Alloc (Root, Type, Real_Allocator, Real_Desallocator, Data); + + if (ND_ERROR(rc)) return rc; + + (*Root)->Own_Value = Own_Value; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: pointeur sur la racine de la structure de données à détruire */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Close_I ( NDT_Root * Root ) +{ + NDT_Status rc; + + /* On supprime toutes les valeurs de la structure */ + + rc = ND_DataStruct_Traverse_I (Root, NDD_CMD_DELETE_VALUE, NULL); + + if (ND_ERROR (rc)) return rc; + + return ND_Root_Free (Root); +} + +/*------------------------------------------------------------------------------*/ +/* Réorganisation d'une structure de données */ +/* - ordonnancement d'une liste non ordonnée */ +/* - réquilibrage d'un arbre non auto-équilibré */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à supprimer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Reorg_I ( NDT_Root * Root ) +{ + if (ND_IS_LIST(Root)) + { + if (!ND_IS_ORDERED(Root)) return ND_List_Sort (Root); + else return NDS_OK; + } + + if (ND_IS_TREE(Root)) return ND_Tree_Equalize (Root); + + sprintf (ND_Error_Msg, "Error ND_DataStruct_Reorg : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + return NDS_ERRAPI; +} + +/*------------------------------------------------------------------------------*/ +/* Parcours de tous les noeuds d'une structure de données et exécution d'une */ +/* commande sur chacun d'eux */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à parcourir */ +/* (I) Command : Commande à exécuter sur chaque noeud traversé */ +/* (I) Data : pointeur de données utilisateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Traverse_I ( NDT_Root * Root, NDT_Command Command, void * Data ) +{ + NDT_Status rc; + NDT_Node * Node, * Next_Node; + + if (Command == NDD_CMD_SUM_VALUES) *((int *)(Data)) = 0; + + ND_Node_First_Get_I (Root, &Node); + + while (Node) + { + Next_Node = NULL; + ND_Node_Next_Get_I (Node, &Next_Node); + + switch (Command) + { + case NDD_CMD_DELETE_VALUE: + + /* On détruit la valeur si la structure est propriétaire de ses valeurs (TRUE par défaut) */ + + if (Root->Own_Value == TRUE) + { + rc = ND_Value_Free_I (Root, Node->Value); + if (ND_ERROR(rc)) return rc; + } + + rc = ND_Node_Remove_I (Node); + if (ND_ERROR(rc)) return rc; + + rc = ND_Node_Free (Root, Node); + if (ND_ERROR(rc)) return rc; + + break; + + case NDD_CMD_SUM_VALUES: + + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_SUM_VALUES, Node->Value, (int *)Data); + if (ND_ERROR(rc)) return rc; + + break; + + case NDD_CMD_PRINT_VALUE: + + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_PRINT_VALUE, Node->Value, (FILE *)Data); + if (ND_ERROR(rc)) return rc; + + fprintf ((FILE *)Data, "\n"); + break; + + default: + + rc = ND_Manager_Exec_I (Root->Manager, Command, Root, Node->Value, Data); + if (ND_ERROR(rc)) return rc; + + break; + } + + Node = Next_Node; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Conversion d'une structure de données d'un type en un autre */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à convertir */ +/* (I) Target_Type : type de structure cible */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Convert_I ( NDT_Root * Root, NDT_DataStruct_Type Target_Type) +{ + NDT_Status rc; + + switch (Root->Type & NDD_DS_MSK) + { + case NDD_DS_LIST: + + switch (Target_Type) + { + case (NDD_DS_LIST | NDD_MN_ORDERED): + + rc = ND_List_Sort (Root); + if (ND_ERROR(rc)) return rc; + if (rc == NDS_OK) Root->Type = Target_Type; + + return rc; + + case (NDD_DS_TREE | NDD_MN_AUTO_EQU): + + rc = ND_List_Sort (Root); + if (rc != NDS_OK) return rc; + rc = ND_Tree_Make (Root); + if (ND_ERROR(rc)) return rc; + if (rc == NDS_OK) Root->Type = Target_Type; + + return rc; + + default: + return NDS_OK; + } + + break; + + case NDD_DS_TREE: + + switch (Target_Type) + { + case (NDD_DS_LIST | NDD_MN_ORDERED): + case (NDD_DS_LIST | NDD_MN_FIFO): + case (NDD_DS_LIST | NDD_MN_FILO): + + rc = ND_List_Make (Root); + if (ND_ERROR(rc)) return rc; + if (rc == NDS_OK) Root->Type = Target_Type; + + default: + return NDS_OK; + } + + break; + + default: + sprintf (ND_Error_Msg, "Error ND_DataStruct_Reorg : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affichage d'informations sur une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Info_Print_I ( NDT_Root * Root, FILE * Out ) +{ + return ND_Manager_Exec_I (Root->Manager, NDD_CMD_PRINT_INFO, Root, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Affichage d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à afficher */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Print_I ( NDT_Root * Root, FILE * Out ) +{ + return ND_DataStruct_Traverse_I (Root, NDD_CMD_PRINT_VALUE, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Function de réparation d'une structure : */ +/* - vérifie que tous les noeuds sont correctement liés les uns aux autres */ +/* - corrige les informations statistiques de la racine */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (O) Nb_Detected : pointeur sur le nombre d'erreurs détectées */ +/* (O) Nb_Corrected : pointeur sur le nombre d'erreurs corrigées */ +/* (I) Out : flux de sortie du rapport */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Check_I ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + if (ND_IS_LIST(Root)) + ND_List_Check (Root, Nb_Detected, Nb_Corrected, Out); + else if (ND_IS_TREE(Root)) + ND_Tree_Check (Root, Nb_Detected, Nb_Corrected, Out); + else + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Check : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + (*Nb_Detected)++; + return NDS_ERRAPI; + } + + /* Affichage du résultat de la procédure de vérification */ + + if (*Nb_Detected == 0) + fprintf (Out, "No error detected in the node structure\n"); + else + fprintf (Out, "%d/%d error(s) corrected in the node structure\n", *Nb_Corrected, *Nb_Detected); + + if (*Nb_Corrected < *Nb_Detected) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affiche la structure de données et ses informations statistiques */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Dump_I ( NDT_Root * Root, FILE * Out ) +{ + NDT_Status rc; + NDT_Node * Node; + + /* Affichage de la racine */ + + fprintf (Out, "Adresse structure = %p\n", Root); + + /* Affichage du contenu de la structure */ + + if (ND_IS_LIST(Root)) + { + Node = Root->Head; + + while (Node) + { + fprintf (Out, " (%p) [", Node); + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_PRINT_VALUE, Node->Value, Out); + if (ND_ERROR(rc)) return rc; + fprintf (Out, "]\n"); + Node = Node->Right; + } + + return NDS_OK; + } + else if (ND_IS_TREE(Root)) + ND_Tree_Recursive_Print (Root->Head, 1, Out); + else + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Dump : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération de la racine d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (O) Root : adresse du pointeur sur la racine à récupérer */ +/* (I) Node : pointeur sur le noeud dont on cherche la racine */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Root_Get_I ( NDT_Root ** Root, NDT_Node * Node ) +{ + *Root = Node->Root; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du premier noeud d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine dont on cherche le premier noeud */ +/* (O) First_Node : adresse du pointeur sur le premier noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_First_Get_I ( NDT_Root * Root, NDT_Node ** First_Node ) +{ + *First_Node = NULL; + + if (ND_IS_LIST(Root)) *First_Node = Root->Head; + + if (ND_IS_TREE(Root)) *First_Node = ND_Tree_Node_First_Recursive_Get (Root->Head); + + if (!*First_Node) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du dernier noeud d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine dont on cherche le dernier noeud */ +/* (O) Last_Node : adresse du pointeur sur le premier noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Last_Get_I ( NDT_Root * Root, NDT_Node ** Last_Node ) +{ + *Last_Node = NULL; + + if (ND_IS_LIST(Root)) *Last_Node = Root->Queue; + + if (ND_IS_TREE(Root)) *Last_Node = ND_Tree_Node_Last_Recursive_Get (Root->Head); + + if (!*Last_Node) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du noeud suivant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud dont on cherche le suivant */ +/* (O) Next_Node : adresse du pointeur sur le noeud suivant */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Next_Get_I ( NDT_Node * Node, NDT_Node ** Next_Node ) +{ + if (ND_IS_LIST(Node->Root)) *Next_Node = Node->Right; + + if (ND_IS_TREE(Node->Root)) + { + if (!Node->Right) *Next_Node = ND_Tree_Parent_Next_Recursive_Get (Node); + else *Next_Node = ND_Tree_Node_First_Recursive_Get (Node->Right); + } + + if (!*Next_Node) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du noeud précédant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud dont on cherche le précédant */ +/* (O) Prev_Node : adresse du pointeur sur le noeud suivant */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Previous_Get_I ( NDT_Node * Node, NDT_Node ** Prev_Node ) +{ + if (ND_IS_LIST(Node->Root)) *Prev_Node = Node->Left; + + if (ND_IS_TREE(Node->Root)) + { + if (!Node->Left) *Prev_Node = ND_Tree_Parent_Previous_Recursive_Get (Node); + else *Prev_Node = ND_Tree_Node_Last_Recursive_Get (Node->Left); + } + + if (!*Prev_Node) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Node : pointeur sur le noeud à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Add_I ( NDT_Root * Root, NDT_Node * Node ) +{ + if (ND_IS_LIST(Root)) return ND_List_Node_Add (Root, Node); + else if (ND_IS_TREE(Root)) return ND_Tree_Node_Add (Root, Node); + else + { + sprintf (ND_Error_Msg, "Error ND_Node_Add : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return NDS_KO; +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'un noeud dans une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Node: pointeur sur le noeud à supprimer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Remove_I ( NDT_Node * Node ) +{ + NDT_Root * Root; + + Root = Node->Root; + + if (ND_IS_LIST(Root)) return ND_List_Node_Remove (Node); + else if (ND_IS_TREE(Root)) + { + NDT_Node ** Tmp; + + /* On récupère l'adresse du lien entre le noeud à supprimer et son père */ + + if (Node->Parent) + { + /* Cas général */ + + if (Node == Node->Parent->Left) Tmp = &(Node->Parent->Left); + else Tmp = &(Node->Parent->Right); + } + else + { + /* Cas du noeud racine */ + + Tmp = NULL; + } + + if (Node->Right) + { + NDT_Node * Right_Node = Node->Right; + NDT_Node * Left_Node = Node->Left; + NDT_Node * First_Node; + + /* + On sauve le fils gauche du noeud à supprimer dans un pointeur de + sauvegarde pour pouvoir le récupérer au cas où la procédure serait + interrompue (recovery). + */ + + Root->Save = Left_Node; + + /* On remplace le noeud supprimé par son sous-arbre droit */ + + if (!Tmp) Root->Head = Root->Queue = Node->Right; + else *Tmp = Node->Right; + + Right_Node->Parent = Node->Parent; + + /* On attache le sous-arbre gauche au premier noeud du sous-arbre droit */ + + if (Root->Save) + { + First_Node = ND_Tree_Node_First_Recursive_Get (Right_Node); + + First_Node->Left = Root->Save; + + Root->Save->Parent = First_Node; + + Root->Save = NULL; + } + } + else + { + /* On remplace le noeud supprimé par son sous-arbre gauche */ + + if (!Tmp) Root->Head = Root->Queue = Node->Left; + else *Tmp = Node->Left; + + if (Node->Left) Node->Left->Parent = Node->Parent; + } + + Root->Node_Number--; + + /* Pas de mise à jour des informations de profondeur : trop coûteux */ + + Node->Left = NULL; + Node->Right = NULL; + Node->Parent = NULL; + Node->Root = NULL; + } + else + { + sprintf (ND_Error_Msg, "Error ND_Node_Remove : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Recherche un noeud à partir d'une valeur */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'abre */ +/* (O) Node : adresse du pointeur sur le noeud à récuperer */ +/* (I) Value : pointeur sur la valeur à rechercher */ +/* (I) Data : pointeur de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Find_I ( NDT_Root * Root, NDT_Node ** Node, void * Value, void * Data ) +{ + if (ND_IS_LIST(Root)) *Node = ND_List_Node_Find (Root, Value, Data); + else if (ND_IS_TREE(Root)) *Node = ND_Tree_Node_Find (Root, Value, Data); + else + { + sprintf (ND_Error_Msg, "Error ND_Node_Find : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + } + + if (!*Node) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Allocation d'une valeur d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (O) Value : adresse d'un pointeur sur la valeur à allouer */ +/* (I) ... : arguments relatifs à l'allocation de la valeur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Alloc_I ( NDT_Root * Root, void ** Value, ... ) +{ + NDT_Status rc; + va_list Args; + + /* Récupération des arguments pour l'allocation de la valeur */ + + va_start (Args, Value); + + /* Appel du manager */ + + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_MAKE_VALUE, Root, Value, Args); + + va_end (Args); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une valeur à une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Value : pointeur sur la valeur à ajouter à la structure de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Add_I ( NDT_Root * Root, void * Value ) +{ + if (ND_IS_LIST(Root)) return ND_List_Value_Add (Root, Value); + else if (ND_IS_TREE(Root)) return ND_Tree_Value_Add (Root, Value); + else + { + sprintf (ND_Error_Msg, "Error ND_Value_Add : unknown structure type (%d)", Root->Type); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return NDS_KO; +} + +/*------------------------------------------------------------------------------*/ +/* Suppression du premier noeud correspondant à une valeur donnée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Reference_Value : pointeur sur la valeur de référence */ +/* (I) Removed_Value : adresse d'un pointeur sur la valeur supprimée */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Remove_I ( NDT_Root * Root, void * Reference_Value, void ** Removed_Value ) +{ + NDT_Status rc; + struct NDT_Node * Node; + + *Removed_Value = NULL; + + /* Recherche du premier noeud correspondant à la valeur de référence */ + + rc = ND_Node_Find_I (Root, &Node, Reference_Value, NULL); + if (ND_ERROR(rc)) return rc; + + if (!Node) return NDS_KO; + + *Removed_Value = Node->Value; + + /* Retrait du noeud de la structure */ + + rc = ND_Node_Remove_I (Node); + if (ND_ERROR(rc)) return rc; + + /* Désallocation du noeud */ + + rc = ND_Node_Free (Root, Node); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'une valeur d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Value: pointeur sur la valeur à désallouer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Free_I ( NDT_Root * Root, void * Value ) +{ + return ND_Manager_Exec_I (Root->Manager, NDD_CMD_DELETE_VALUE, Root, Value); +} + + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction Manager dont le nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction manager à exécuter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Manager_Exec_I ( const char * Function, ... ) +{ + NDT_Manager * Manager; + NDT_Status rc; + va_list Args; + + va_start (Args, Function); + + Manager = (NDT_Manager *) ND_Symbol_Find (Function); + + rc = Manager (Args); + + va_end (Args); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction d'allocation dont le nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction à exécuter */ +/* (O) Ptr : adresse d'un pointeur sur la zone à allouer */ +/* (I) Size : taille de la zone à allouer */ +/* (I) Data : données utilisateur utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Allocator_Exec_I ( const char * Function, void ** Ptr, size_t Size, void * Data ) +{ + NDT_Allocator * Allocator; + + *Ptr = NULL; + + Allocator = (NDT_Allocator *) ND_Symbol_Find (Function); + + return Allocator (Size, Ptr, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction de désallocation dont nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction à exécuter */ +/* (I) Ptr : adresse de la zone à désallouer */ +/* (I) Data : données utilisateur utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Desallocator_Exec_I ( const char * Function, void * Ptr, void * Data ) +{ + NDT_Desallocator * Desallocator; + + Desallocator = (NDT_Desallocator *) ND_Symbol_Find (Function); + + return Desallocator (Ptr, Data); +} + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS SECURISEES (ND_MODE = 0) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Initialisation du contexte de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Open_C ( int Debug_Mode ) +{ + return ND_Library_Open_I (Debug_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture du contexte de la librairie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Close_C ( void ) +{ + return ND_Library_Close_I (); +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie de l'affichage des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Library_Stderr_Set_C ( FILE * Out ) +{ + return ND_Library_Stderr_Set_I (Out); +} + +/*------------------------------------------------------------------------------*/ +/* Création d'une nouvelle structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: adresse d'un pointeur sur la racine de la nouvelle structure */ +/* (I) Type: type de la structure.de données (liste ou arbre binaire) */ +/* (I) Allocator: pointeur vers la fonction d'allocation */ +/* (I) Desallocator: pointeur vers la fonction de désallocation */ +/* (I) Data : pointeur de données utiles à l'allocateur */ +/* (I) Own_Value : indique si la structure est propriétaire de ses valeurs */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Open_C ( NDT_Root ** Root, NDT_DataStruct_Type Type, const char * Allocator, const char * Desallocator, void * Data, int Own_Value ) +{ + return ND_DataStruct_Open_I (Root, Type, Allocator, Desallocator, Data, Own_Value); +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) Root: pointeur sur la racine de la structure de données à détruire */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Close_C ( NDT_Root * Root ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Close : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Close_I (Root); +} + +/*------------------------------------------------------------------------------*/ +/* Réorganisation d'une structure de données */ +/* - ordonnancement d'une liste non ordonnée */ +/* - réquilibrage d'un arbre non auto-équilibré */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à supprimer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Reorg_C ( NDT_Root * Root ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Reorg : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Reorg_I (Root); +} + +/*------------------------------------------------------------------------------*/ +/* Parcours de tous les noeuds d'une structure de données et exécution d'une */ +/* commande sur chacun d'eux */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à parcourir */ +/* (I) Command : Commande à exécuter sur chaque noeud traversé */ +/* (I) Data : pointeur de données utilisateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Traverse_C ( NDT_Root * Root, NDT_Command Command, void * Data ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Traverse : structure root is null"); + ND_Error_Print (); + return NDS_KO; + } + + return ND_DataStruct_Traverse_I (Root, Command, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Conversion d'une structure de données d'un type en un autre */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à convertir */ +/* (I) Target_Type : type de structure cible */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Convert_C ( NDT_Root * Root, NDT_DataStruct_Type Target_Type) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Convert : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Convert_I (Root, Target_Type); +} + +/*------------------------------------------------------------------------------*/ +/* Affichage d'informations sur une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Info_Print_C ( NDT_Root * Root, FILE * Out ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Print : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Out) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Print : the stream descriptor is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Info_Print_I (Root, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Affichage d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données à afficher */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Print_C ( NDT_Root * Root, FILE * Out ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Print : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Out) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Print : the stream descriptor is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Print_I (Root, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Function de réparation d'une structure : */ +/* - vérifie que tous les noeuds sont correctement liés les uns aux autres */ +/* - corrige les informations statistiques de la racine */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (O) Nb_Detected : pointeur sur le nombre d'erreurs détectées */ +/* (O) Nb_Corrected : pointeur sur le nombre d'erreurs corrigées */ +/* (I) Out : flux de sortie du rapport */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Check_C ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Check : structure root is null"); + ND_Error_Print (); + (*Nb_Detected)++; + return NDS_ERRAPI; + } + + if (!Out) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Check : the stream descriptor is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Check_I (Root, Nb_Detected, Nb_Corrected, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Affiche la structure de données et ses informations statistiques */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (I) Out : flux de sortie */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_DataStruct_Dump_C ( NDT_Root * Root, FILE * Out ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Dump : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Out) + { + sprintf (ND_Error_Msg, "Error ND_DataStruct_Dump : the stream descriptor is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_DataStruct_Dump_I (Root, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération de la racine d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (O) Root : adresse du pointeur sur la racine à récupérer */ +/* (I) Node : pointeur sur le noeud dont on cherche la racine */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Root_Get_C ( NDT_Root ** Root, NDT_Node * Node ) +{ + if (!Node) + { + sprintf (ND_Error_Msg, "Error ND_Node_Root_Get : node is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Root_Get_I (Root, Node); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du premier noeud d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine dont on cherche le premier noeud */ +/* (O) First_Node : adresse du pointeur sur le premier noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_First_Get_C ( NDT_Root * Root, NDT_Node ** First_Node ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Node_First_Get : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_First_Get_I (Root, First_Node); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du dernier noeud d'une structure */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine dont on cherche le dernier noeud */ +/* (O) Last_Node : adresse du pointeur sur le premier noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Last_Get_C ( NDT_Root * Root, NDT_Node ** Last_Node ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Node_Last_Get : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Last_Get_I (Root, Last_Node); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du noeud suivant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud dont on cherche le suivant */ +/* (O) Next_Node : adresse du pointeur sur le noeud suivant */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Next_Get_C ( NDT_Node * Node, NDT_Node ** Next_Node ) +{ + if (!Node) + { + sprintf (ND_Error_Msg, "Error ND_Node_Next_Get : node is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Next_Get_I (Node, Next_Node); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du noeud précédant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud dont on cherche le précédant */ +/* (O) Prev_Node : adresse du pointeur sur le noeud suivant */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Previous_Get_C ( NDT_Node * Node, NDT_Node ** Prev_Node ) +{ + if (!Node) + { + sprintf (ND_Error_Msg, "Error ND_Node_Previous_Get : node is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Previous_Get_I (Node, Prev_Node); +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Node : pointeur sur le noeud à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Add_C ( NDT_Root * Root, NDT_Node * Node ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Node_Add : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Node) + { + sprintf (ND_Error_Msg, "Error ND_Node_Add : the node to add is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Add_I (Root, Node); +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'un noeud dans une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Node: pointeur sur le noeud à supprimer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Remove_C ( NDT_Node * Node ) +{ + if (!Node) + { + sprintf (ND_Error_Msg, "Error ND_Node_Remove : the node to remove is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Remove_I (Node); +} + +/*------------------------------------------------------------------------------*/ +/* Recherche un noeud à partir d'une valeur */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'abre */ +/* (O) Node : adresse du pointeur sur le noeud à récuperer */ +/* (I) Value : pointeur sur la valeur à rechercher */ +/* (I) Data : pointeur de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Find_C ( NDT_Root * Root, NDT_Node ** Node, void * Value, void * Data ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Node_Find : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Value) + { + sprintf (ND_Error_Msg, "Error ND_Node_Find : the value to find is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Node_Find_I (Root, Node, Value, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Allocation d'une valeur d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (O) Value : adresse d'un pointeur sur la valeur à allouer */ +/* (I) ... : arguments relatifs à l'allocation de la valeur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Alloc_C ( NDT_Root * Root, void ** Value, ... ) +{ + NDT_Status rc; + va_list Args; + + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Value_Alloc : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + /* Récupération des arguments pour l'allocation de la valeur */ + + va_start (Args, Value); + + /* Appel du manager */ + + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_MAKE_VALUE, Root, Value, Args); + + va_end (Args); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une valeur à une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Value : pointeur sur la valeur à ajouter à la structure de données */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Add_C ( NDT_Root * Root, void * Value ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Value_Add : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Value) + { + sprintf (ND_Error_Msg, "Error ND_Value_Add : the value to add is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Value_Add_I (Root, Value ); +} + +/*------------------------------------------------------------------------------*/ +/* Suppression du premier noeud correspondant à une valeur donnée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure de données */ +/* (I) Reference_Value : pointeur sur la valeur de référence */ +/* (I) Removed_Value : adresse d'un pointeur sur la valeur supprimée */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Remove_C ( NDT_Root * Root, void * Reference_Value, void ** Removed_Value ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Value_Remove : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Reference_Value) + { + sprintf (ND_Error_Msg, "Error ND_Value_Remove : the reference value is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + return ND_Value_Remove_I (Root, Reference_Value, Removed_Value); +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'une valeur d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure de données */ +/* (I) Value: pointeur sur la valeur à désallouer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Value_Free_C ( NDT_Root * Root, void * Value ) +{ + if (!Root) + { + sprintf (ND_Error_Msg, "Error ND_Value_Free : structure root is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + if (!Value) + { + sprintf (ND_Error_Msg, "Error ND_Value_Free : the value to free is null"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + /* Appel du manager */ + + return ND_Value_Free_I (Root, Value); +} + + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction Manager dont le nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction manager à exécuter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Manager_Exec_C ( const char * Function, ... ) +{ + NDT_Manager * Manager; + NDT_Status rc; + va_list Args; + + if (!Function || !*Function) + { + sprintf (ND_Error_Msg, "Error ND_Manager_Exec : undefined function name"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + va_start (Args, Function); + + Manager = (NDT_Manager *) ND_Symbol_Find (Function); + + if (!Manager) return NDS_ERRAPI; + + rc = Manager (Args); + + va_end (Args); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction d'allocation dont le nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction à exécuter */ +/* (O) Ptr : adresse d'un pointeur sur la zone à allouer */ +/* (I) Size : taille de la zone à allouer */ +/* (I) Data : données utilisateur utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Allocator_Exec_C ( const char * Function, void ** Ptr, size_t Size, void * Data ) +{ + NDT_Allocator * Allocator; + + *Ptr = NULL; + + if (!Function || !*Function) + { + sprintf (ND_Error_Msg, "Error ND_Allocator_Exec : undefined function name"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + Allocator = (NDT_Allocator *) ND_Symbol_Find (Function); + + if (!Allocator) return NDS_ERRAPI; + + return Allocator (Size, Ptr, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Exécution d'une fonction de désallocation dont nom est passé en paramètre */ +/*------------------------------------------------------------------------------*/ +/* (I) Function : nom de la fonction à exécuter */ +/* (I) Ptr : adresse de la zone à désallouer */ +/* (I) Data : données utilisateur utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Desallocator_Exec_C ( const char * Function, void * Ptr, void * Data ) +{ + NDT_Desallocator * Desallocator; + + if (!Function || !*Function) + { + sprintf (ND_Error_Msg, "Error ND_Desallocator_Exec : undefined function name"); + ND_Error_Print (); + return NDS_ERRAPI; + } + + Desallocator = (NDT_Desallocator *) ND_Symbol_Find (Function); + + if (!Desallocator) return NDS_ERRAPI; + + return Desallocator (Ptr, Data); +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PRIVEES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Recherche d'un symbole */ +/*------------------------------------------------------------------------------*/ +void * ND_Symbol_Find ( const char * Symbol_Name ) +{ + struct Symbol * Symbol; + void * Ptr = NULL; + + /* Recherche du symbole dans la table des symboles locale */ + + Symbol = Symbol_Table; + while (Symbol) + { + if (!strcmp (Symbol->Name, Symbol_Name)) return Symbol->Ptr; + else Symbol = Symbol->Next; + } + + /* Si le symbole n'a pas été trouvée dans la table des symboles locale, on l'y ajoute */ + + Ptr = dlsym (RTLD_DEFAULT, (const char *) Symbol_Name); + if (!Ptr) + { + sprintf (ND_Error_Msg, "Error ND_Symbol_Find : unable to find \"%s\"' in symbol table (%s)", Symbol_Name, dlerror ()); + ND_Error_Print (); + return NULL; + } + + Symbol = (struct Symbol *) malloc (sizeof (struct Symbol)); + if (Symbol) + { + Symbol->Name = strdup (Symbol_Name); + Symbol->Ptr = Ptr; + Symbol->Next = Symbol_Table; + Symbol_Table = Symbol; + } + + return Ptr; +} + +/*------------------------------------------------------------------------------*/ +/* Allocation d'un noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/* (O) Node : adresse du pointeur sur le nouveau noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Alloc ( NDT_Root * Root, NDT_Node ** Node ) +{ + NDT_Status rc; + + rc = ND_Allocator_Exec_I (Root->Allocator, (void **)Node, sizeof (NDT_Node), Root->User); + + if (ND_ERROR(rc)) return rc; + + (*Node)->Parent = NULL; + (*Node)->Left = NULL; + (*Node)->Right = NULL; + (*Node)->Root = NULL; + (*Node)->Value = NULL; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation d'un noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Root: pointeur sur la racine de la structure */ +/* (I) Node : pointeur sur le noeud à détruire */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Free ( NDT_Root * Root, NDT_Node * Node ) +{ + return ND_Desallocator_Exec_I (Root->Desallocator, Node, Root->User); +} + +/*------------------------------------------------------------------------------*/ +/* Désallocation de la racine d'une structure de donnée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine à détruire */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Root_Free ( NDT_Root * Root ) +{ + return ND_Desallocator_Exec_I (Root->Desallocator, Root, Root->User); +} + +/*------------------------------------------------------------------------------*/ +/* Allocation d'une racine de structure de données */ +/*------------------------------------------------------------------------------*/ +/* (O) New_Root: adresse du pointeur sur la nouvelle racine */ +/* (I) Type: type de la structure de données */ +/* (I) Allocator: pointeur vers la fonction d'allocation */ +/* (I) Desallocator: pointeur vers la fonction de désallocation */ +/* (I) Data : pointeur de données utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Root_Alloc ( NDT_Root ** Root, NDT_DataStruct_Type Type, const char * Allocator, const char * Desallocator, void * Data ) +{ + NDT_Status rc; + + rc = ND_Allocator_Exec_I (Allocator, (void **)Root, sizeof (NDT_Root), Data); + + if (ND_ERROR(rc)) return rc; + + (*Root)->Type = Type; + + (*Root)->Head = NULL; + (*Root)->Queue = NULL; + (*Root)->Save = NULL; + + (*Root)->Max_Dif = DEF_MAX_DIF; + + (*Root)->Node_Number = 0; + (*Root)->Max_Depth = 0; + (*Root)->Min_Depth = HUGE_LONG; + (*Root)->Nb_Equ = 0; + (*Root)->User = Data; + (*Root)->Own_Value = TRUE; /* par défaut, une structure de données est propriétaire de ses valeurs */ + + strcpy ((*Root)->Manager, "Default_Manager"); + strcpy ((*Root)->Allocator, Allocator); + strcpy ((*Root)->Desallocator, Desallocator); + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à une liste chaînée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste */ +/* (I) New_Node : pointeur sur le noeud à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Node_Add ( NDT_Root * Root, NDT_Node * New_Node ) +{ + /* Ajout dans une liste triée */ + + if (ND_IS_ORDERED(Root)) + { + NDT_Node * Node; + NDT_Status rc; + + New_Node->Root = Root; + New_Node->Parent = New_Node->Left = New_Node->Right = NULL; + + /* + Une liste triée peut être orientée de 2 manières : + + - FIFO : un noeud sera inséré APRES un noeud de même valeur (par défaut) + - FILO : un noeud sera inséré AVANT un noeud de même valeur + */ + + if (ND_IS_FILO(Root)) + { + /* Pour une liste triée orientée FILO, on parcourt la liste en sens normal */ + + Node = Root->Head; + + while (Node) + { + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_COMP_VALUE, New_Node->Value, Node->Value); + + if (rc == NDS_GREATER) + Node = Node->Right; + else + { + /* On insère avant le noeud courant si le nouveau noeud est de valeur inférieure ou égale */ + + New_Node->Left = Node->Left; + New_Node->Right = Node; + + if (!Node->Left) Root->Head = New_Node; + else Node->Left->Right = New_Node; + + Node->Left = New_Node; + Node = NULL; + } + } + + /* Insertion en queue de liste si le noeud n'a pas été inséré */ + + if (!New_Node->Left && !New_Node->Right) + { + if (!Root->Queue) Root->Head = Root->Queue = New_Node; + else + { + Root->Queue->Right = New_Node; + New_Node->Left = Root->Queue; + Root->Queue = New_Node; + } + } + } + else + { + /* Pour une liste triée orientée FIFO, on parcourt la liste dans le sens inverse */ + + Node = Root->Queue; + while (Node) + { + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_COMP_VALUE, New_Node->Value, Node->Value); + + /* On insère après le noeud courant si le nouveau noeud est de valeur strictement supérieure ou égale */ + + if (rc == NDS_LOWER) Node = Node->Left; + else + { + New_Node->Left = Node; + New_Node->Right = Node->Right; + + if (!Node->Right) Root->Queue = New_Node; + else Node->Right->Left = New_Node; + + Node->Right = New_Node; + Node = NULL; + } + } + + /* Insertion en tête de liste si le noeud n'a pas été inséré */ + + if (!New_Node->Left && !New_Node->Right) + { + if (!Root->Head) Root->Head = Root->Queue = New_Node; + else + { + Root->Head->Left = New_Node; + New_Node->Right = Root->Head; + Root->Head = New_Node; + } + } + } + + Root->Node_Number++; + + return NDS_OK; + } + else + { + /* FIFO = ajout en queue de liste */ + + if (ND_IS_FIFO(Root)) + { + New_Node->Root = Root; + New_Node->Parent = NULL; + New_Node->Left = Root->Queue; + New_Node->Right = NULL; + + if (!Root->Head) Root->Head = New_Node; + else Root->Queue->Right = New_Node; + + Root->Queue = New_Node; + Root->Node_Number++; + + return NDS_OK; + } + + /* FILO = ajout en tête de liste */ + + if (ND_IS_FILO(Root)) + { + + New_Node->Root = Root; + + New_Node->Parent = NULL; + New_Node->Left = NULL; + New_Node->Right = Root->Head; + + if (!Root->Queue) Root->Queue = New_Node; + else Root->Head->Left = New_Node; + + Root->Head = New_Node; + Root->Node_Number++; + + return NDS_OK; + } + } + + printf ("ND_List_Node_Add : unknown list type (%d)\n", Root->Type); + return NDS_ERRAPI; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une nouvelle valeur à une liste */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste */ +/* (I) Value : pointeur sur la valeur à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Value_Add ( NDT_Root * Root, void * Value ) +{ + NDT_Status rc; + NDT_Node * Node; + + rc = ND_Node_Alloc (Root, &Node); + + if (ND_ERROR(rc)) return rc; + + Node->Value = Value; + + return ND_List_Node_Add (Root, Node); +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à un arbre binaire */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'arbre */ +/* (I) Value : pointeur sur la valeur à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_Value_Add ( NDT_Root * Root, void * Value ) +{ + NDT_Status rc; + NDT_Node * Node; + + rc = ND_Node_Alloc (Root, &Node); + + if (ND_ERROR(rc)) return rc; + + Node->Value = Value; + + return ND_Tree_Node_Add (Root, Node); +} + +/*------------------------------------------------------------------------------*/ +/* Recherche une valeur dans une liste et retourne le noeud correspondant */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste */ +/* (I) Value : pointeur sur la valeur à rechercher */ +/* (I) Data : pointeur de données */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_List_Node_Find ( NDT_Root * Root, void * Value, void * Data ) +{ + NDT_Node * Node; + NDT_Status rc; + + Node = Root->Head; + + if (ND_IS_ORDERED(Root)) + { + /* Pour les listes triées, la recherche peut être optimisée */ + + while (Node) + { + rc = ND_Manager_Exec_I (Root->Manager, NDD_CMD_COMP_VALUE, Value, Node->Value, Data); + + switch (rc) + { + case NDS_EQUAL: + + return Node; + + case NDS_LOWER: + + /* Ce n'est pas a peine de continuer car on a déjà dépassé la valeur recherchée */ + + return NULL; + + case NDS_GREATER: + + Node = Node->Right; + break; + } + } + } + else + { + /* Pour les listes non triées, il faut parcourir toute la liste */ + + while (Node && ND_Manager_Exec_I (Root->Manager, NDD_CMD_COMP_VALUE, Value, Node->Value, Data) != NDS_EQUAL) + Node = Node->Right; + } + + return Node; +} + +/*------------------------------------------------------------------------------*/ +/* Recherche un noeud dans un arbre et retourne le pointeur sur le noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'abre */ +/* (I) Value : pointeur sur la valeur à rechercher */ +/* (I) Data : pointeur de données */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------ Recursive Kernel ------------------------------*/ + +NDT_Node * ND_Tree_Node_Recursive_Find ( NDT_Node * Node, void * Value, void * Data ) +{ + NDT_Status Answer; + + if (!Node) return NULL; + + Answer = ND_Manager_Exec_I (Node->Root->Manager, NDD_CMD_COMP_VALUE, Value, Node->Value, Data); + + /* Noeud trouvé */ + + if (Answer == NDS_EQUAL) return Node; + + /* Continuation de la recherche par appel récursif */ + + if (Answer == NDS_LOWER) return ND_Tree_Node_Recursive_Find (Node->Left, Value, Data); + + if (Answer == NDS_GREATER) return ND_Tree_Node_Recursive_Find (Node->Right, Value, Data); + + return NULL; +} + +/*-------------------------------- main body ---------------------------------*/ + +NDT_Node * ND_Tree_Node_Find ( NDT_Root * Root, void * Value, void * Data ) +{ + return ND_Tree_Node_Recursive_Find (Root->Head, Value, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Recherche du premier noeud parent situé après */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_Tree_Parent_Next_Recursive_Get ( NDT_Node * Node ) +{ + if (!Node->Parent) return NULL; + + if (Node == Node->Parent->Right) return ND_Tree_Parent_Next_Recursive_Get (Node->Parent); + + return Node->Parent; +} + +/*------------------------------------------------------------------------------*/ +/* Recherche du premier noeud parent situé avant */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_Tree_Parent_Previous_Recursive_Get ( NDT_Node * Node ) +{ + if (!Node->Parent) return NULL; + + if (Node == Node->Parent->Left) return ND_Tree_Parent_Previous_Recursive_Get (Node->Parent); + + return Node->Parent; +} + +/*------------------------------------------------------------------------------*/ +/* Supprime le noeud d'une liste */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud à supprimer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Node_Remove ( NDT_Node * Node ) +{ + if (!Node->Left) Node->Root->Head = Node->Right; + else Node->Left->Right = Node->Right; + + if (!Node->Right) Node->Root->Queue = Node->Left; + else Node->Right->Left = Node->Left; + + Node->Root->Node_Number--; + + Node->Left = NULL; + Node->Right = NULL; + Node->Root = NULL; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Conversion d'un arbre en liste chaînée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine du la structure à convertir */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------- Recursive Kernel -----------------------------*/ + +NDT_Status ND_List_Recursive_Make ( NDT_Node * Node, NDT_Root * Root ) +{ + NDT_Node * Right_Node; + + if (!Node) return NDS_OK; + + if (ND_List_Recursive_Make (Node->Left, Root) != NDS_OK) return NDS_KO; + + Right_Node = Node->Right; + + if (ND_List_Node_Add (Root, Node) != NDS_OK) return NDS_KO; + + return ND_List_Recursive_Make (Right_Node, Root); +} + +/*--------------------------------- main body --------------------------------*/ +NDT_Status ND_List_Make ( NDT_Root * Root ) +{ + NDT_Node * Node; + + Node = Root->Head; + + Root->Head = NULL; + Root->Queue = NULL; + Root->Max_Dif = DEF_MAX_DIF; + Root->Node_Number = 0; + Root->Max_Depth = 0; + Root->Min_Depth = HUGE_LONG; + Root->Nb_Equ = 0; + Root->Type = NDD_DS_LIST | NDD_MN_FIFO; + + return ND_List_Recursive_Make (Node, Root); +} + +/*------------------------------------------------------------------------------*/ +/* Conversion d'une structure en arbre binaire */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine du la structure à convertir */ +/* (I) Type : type du futur arbre */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------- Recursive Kernel -----------------------------*/ + +NDT_Node * ND_Tree_Recursive_Make ( long Depth, long Node_Number, NDT_Node * Node ) +{ + long Middle_Pos, Left_Len, Right_Len, i; + NDT_Node * Left_Node, * Middle_Node, * Right_Node; + + if (!Node) return (NULL); + + /* On calcule le milieu de la liste */ + + Middle_Pos = Node_Number / 2 + 1; + + Middle_Node = Node; + + for (i = 1; i < Middle_Pos; i++) Middle_Node = Middle_Node->Right; + + /* On coupe la liste en deux */ + + if (Middle_Node->Left) + { + Middle_Node->Left->Right = NULL; + Left_Node = Node; + Left_Len = Middle_Pos - 1; + } + else + { + Left_Node = NULL; + Left_Len = 0; + } + + if (Middle_Node->Right) + { + Middle_Node->Right->Left = NULL; + Right_Node = Middle_Node->Right; + Right_Len = Node_Number - Middle_Pos; + } + else + { + Right_Node = NULL; + Right_Len = 0; + } + + /* Construction des sous-arbres */ + + Middle_Node->Left = ND_Tree_Recursive_Make (Depth + 1, Left_Len, Left_Node); + + Middle_Node->Right = ND_Tree_Recursive_Make (Depth + 1, Right_Len, Right_Node); + + if (Middle_Node->Left) Middle_Node->Left->Parent = Middle_Node; + + if (Middle_Node->Right) Middle_Node->Right->Parent = Middle_Node; + + /* Mise à jour des informations statistiques de la structure */ + + Middle_Node->Root->Node_Number++; + + if (!Middle_Node->Left && !Middle_Node->Right) + { + /* + Si le noeud courant est une feuille, on met éventuellement à jour + les longueurs minimale et maximale des branches de l'arbre + */ + + if (Depth > Middle_Node->Root->Max_Depth) Middle_Node->Root->Max_Depth = Depth; + + if (Depth < Middle_Node->Root->Min_Depth) Middle_Node->Root->Min_Depth = Depth; + } + + return Middle_Node; +} + +/*--------------------------------- main body --------------------------------*/ + +NDT_Status ND_Tree_Make ( NDT_Root * Root ) +{ + NDT_Status rc; + NDT_Node * Node; + long Node_Number; + + if (ND_IS_ORDERED(Root)) + { + rc = ND_List_Sort (Root); + if (ND_ERROR(rc)) return rc; + } + + Node = Root->Head; + Node_Number = Root->Node_Number; + + Root->Head = NULL; + Root->Queue = NULL; + Root->Max_Dif = DEF_MAX_DIF; + Root->Node_Number = 0; + Root->Max_Depth = 0; + Root->Min_Depth = HUGE_LONG; + Root->Nb_Equ = 0; + Root->Type = NDD_DS_TREE | NDD_MN_AUTO_EQU; + + Root->Head = Root->Queue = ND_Tree_Recursive_Make (1, Node_Number, Node); + + return NDS_OK; +} + +/*----------------------------------------------------------------------------*/ +/* Equilibrage d'un arbre binaire */ +/*----------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'arbre */ +/*----------------------------------------------------------------------------*/ +NDT_Status ND_Tree_Equalize ( NDT_Root * Root ) +{ + NDT_Status rc; + NDT_DataStruct_Type Type; + char Manager[30]; + long Max_Dif, Nb_Equ; + + Type = Root->Type; + strcpy (Manager, Root->Manager); + Max_Dif = Root->Max_Dif; + Nb_Equ = Root->Nb_Equ; + + rc = ND_List_Make (Root); + if (ND_ERROR(rc)) return rc; + + Root->Type = NDD_DS_LIST | NDD_MN_ORDERED; + + rc = ND_Tree_Make (Root); + if (ND_ERROR(rc)) return rc; + + Root->Type = Type; + strcpy (Root->Manager, Manager); + Root->Max_Dif = Max_Dif; + Root->Nb_Equ = Nb_Equ + 1; + + return NDS_OK; +} + +/*----------------------------------------------------------------------------*/ +/* Retourne la profondeur de la plus grande branche à partir d'un noeud */ +/*----------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud */ +/*----------------------------------------------------------------------------*/ +long ND_Tree_MaxDepth_Get ( NDT_Node * Node ) +{ + long Max_Left, Max_Right; + + if (!Node) return 0; + + Max_Left = ND_Tree_MaxDepth_Get (Node->Left); + + Max_Right = ND_Tree_MaxDepth_Get (Node->Right); + + return ( max (Max_Left, Max_Right) + 1 ); +} + +/*----------------------------------------------------------------------------*/ +/* Retourne la profondeur de la plus petite branche à partir d'un noeud */ +/*----------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud */ +/*----------------------------------------------------------------------------*/ +long ND_Tree_MinDepth_Get ( NDT_Node * Node) +{ + long Min_Left, Min_Right; + + if (!Node) return 0; + + Min_Left = ND_Tree_MinDepth_Get (Node->Left); + + Min_Right = ND_Tree_MinDepth_Get (Node->Right); + + return ( min (Min_Left, Min_Right) + 1 ); +} + +/*----------------------------------------------------------------------------*/ +/* Ajoute un noeud à un arbre */ +/*----------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'arbre */ +/* (I) Node : pointeur sur le noeud à ajouter */ +/*----------------------------------------------------------------------------*/ + +/*------------------------------ Recursive Kernel ----------------------------*/ + +void ND_Tree_Node_Recursive_Add ( NDT_Root * Root, NDT_Node * Parent_Node, NDT_Node ** Node, long Depth, NDT_Node * New_Node ) +{ + if (*Node) + { + /* Appel récursif */ + + if (ND_Manager_Exec_I (Root->Manager, NDD_CMD_COMP_VALUE, New_Node->Value, (*Node)->Value) == NDS_LOWER) + ND_Tree_Node_Recursive_Add (Root, (*Node), &((*Node)->Left), Depth + 1, New_Node); + else + ND_Tree_Node_Recursive_Add (Root, (*Node), &((*Node)->Right), Depth + 1, New_Node); + } + else + { + long Max_Depth, Min_Depth; + + /* Rattachement du nouveau noeud à l'arbre */ + + New_Node->Parent = Parent_Node; + New_Node->Root = Root; + + *Node = New_Node; + + /* Mise à jour des informations statistiques de la structure */ + + Root->Node_Number++; + + Max_Depth = ND_Tree_MaxDepth_Get (New_Node); + + Min_Depth = ND_Tree_MinDepth_Get (New_Node); + + if (Max_Depth + Depth - 1 > Root->Max_Depth) Root->Max_Depth = Max_Depth + Depth - 1; + + if (Min_Depth + Depth - 1 < Root->Min_Depth) Root->Min_Depth = Min_Depth + Depth - 1 ; + } +} + +/*-------------------------------- main body ---------------------------------*/ +NDT_Status ND_Tree_Node_Add ( NDT_Root * Root, NDT_Node * Node ) +{ + ND_Tree_Node_Recursive_Add (Root, NULL, &(Root->Head), 1, Node); + + if (ND_IS_AUTO_EQU(Root) && Root->Max_Depth - Root->Min_Depth > Root->Max_Dif) + return ND_Tree_Equalize (Root); + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajoute tous les noeud d'une liste à un arbre */ +/*------------------------------------------------------------------------------*/ +/* (I) Tree_Root : pointeur sur la racine de l'arbre */ +/* (I) List_Root : pointeur sur la racine de la liste */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_List_Add ( NDT_Root * Tree_Root, NDT_Root * List_Root) +{ + NDT_Status rc; + NDT_Node * Node; + + Node = List_Root->Head; + + while (Node) + { + rc = ND_Tree_Node_Add (Tree_Root, Node); + if (ND_ERROR(rc)) return rc; + Node = Node->Right; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affiche toutes les informations d'une structure de données */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la structure */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------- Recursive Kernel -----------------------------*/ + +void ND_Tree_Recursive_Print ( NDT_Node * Node, long Depth, FILE * Out ) +{ + const int BRANCH_LEN = 4; + + if (!Node) return; + + if (Node->Right) + { + ND_Tree_Recursive_Print (Node->Right, Depth + 1, Out); + fprintf (Out, "%*s/\n", (int)(Depth * BRANCH_LEN - 1), ""); + } + + fprintf (Out, "%*s (%p) ", (int)((Depth - 1) * BRANCH_LEN), "", Node); + +/* Affichage des toutes les informations (noeud et valeur) : + + if (Node->Root) fprintf (Out, "Root=%p ", Node->Root); + if (Node->Parent) fprintf (Out, "Parent=%p ", Node->Parent); + if (Node->Left) fprintf (Out, "Left=%p ", Node->Left); + if (Node->Right) fprintf (Out, "Right=%p ", Node->Right); + + fprintf (Out, "Value=["); + ND_Manager_Exec (Node->Root->Manager, NDD_CMD_PRINT_VALUE, Node->Value, Out); + fprintf (Out, "]\n"); +*/ + +/* Affichage de la valeur seule : */ + + ND_Manager_Exec_I (Node->Root->Manager, NDD_CMD_PRINT_VALUE, Node->Value, Out); + fprintf (Out, "\n"); + + if (Node->Left) + { + fprintf (Out, "%*s\\\n", (int)(Depth * BRANCH_LEN - 1), ""); + ND_Tree_Recursive_Print (Node->Left, Depth + 1, Out); + } +} + +/*------------------------------------------------------------------------------*/ +/* Function de comparaison de noeuds (pour le quick sort) */ +/*------------------------------------------------------------------------------*/ +int ND_Node_Compare ( void ** Node1, void ** Node2 ) +{ + NDT_Status rc; + + rc = ND_Manager_Exec_I (Tmp_Root->Manager, NDD_CMD_COMP_VALUE, ((NDT_Node *)(*Node1))->Value, ((NDT_Node *)(*Node2))->Value); + + switch ((int)rc) + { + case NDS_EQUAL: return 0; + case NDS_LOWER: return -1; + case NDS_GREATER: return 1; + default: + sprintf (ND_Error_Msg, "Error ND_Node_Compare : incorrect return code from the manager: %d", rc); + ND_Error_Print (); + return 0; + } +} + +/*----------------------------------------------------------------------------*/ +/* Ordonne une liste chaînée : */ +/*----------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste à trier */ +/*----------------------------------------------------------------------------*/ +NDT_Status ND_List_Sort ( NDT_Root * Root ) +{ + int i; + NDT_Node * Node; + void ** Tab; + + if (Root->Node_Number < 2) return NDS_OK; + + /* Allocation d'un tableau de pointeur de noeuds */ + + Tab = (void **) malloc (Root->Node_Number * sizeof (NDT_Node *)); + + /* On remplit le tableau avec les noeuds de la structure à trier */ + + i = 0; + Node = Root->Head; + while (Node) + { + Tab[i] = Node; + Node = Node->Right; + i++; + } + + /* Tri du tableau de pointeurs de noeuds */ + + Tmp_Root = Root; + + qsort (Tab, (size_t)(Root->Node_Number), sizeof (NDT_Node *), &ND_Node_Compare); + + /* On met à jour les liens entre les noeuds */ + + for (i = 0; i < Root->Node_Number; i++) + { + Node = (NDT_Node *) Tab [i]; + + Node->Left = (i ? (NDT_Node *)(Tab [i - 1]) : NULL); + Node->Right = (i != Root->Node_Number - 1 ? (NDT_Node *)(Tab [i + 1]) : NULL); + } + + Root->Head = (NDT_Node *)(Tab [0]); + Root->Queue = (NDT_Node *)(Tab [Root->Node_Number - 1]); + + /* Désallocation du tableau */ + + free (Tab); + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupère le premier noeud dans un sous-arbre */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud racine du sous-arbre */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_Tree_Node_First_Recursive_Get ( NDT_Node * Node ) +{ + if (!Node) return NULL; + + if (!Node->Left) return Node; + + return ND_Tree_Node_First_Recursive_Get (Node->Left); +} + +/*------------------------------------------------------------------------------*/ +/* Récupère le dernier noeud dans un sous-arbre */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud racine du sous-arbre */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_Tree_Node_Last_Recursive_Get ( NDT_Node * Node ) +{ + if (!Node) return NULL; + + if (!Node->Right) return Node; + + return ND_Tree_Node_Last_Recursive_Get (Node->Right); +} + +/*------------------------------------------------------------------------------*/ +/* Redéfinition de la fonction malloc () avec retour de type NDT_Status */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Malloc ( size_t Size, void ** ptr, void * Data ) +{ + *ptr = malloc (Size); + + if (!*ptr) return NDS_ERRMEM; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Redéfinition de la fonction free () avec retour de type NDT_Status */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Free (void * ptr) +{ + if (!ptr) return NDS_ERRAPI; + + free (ptr); + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Function de vérification d'une liste : */ +/*------------------------------------------------------------------------------*/ +void ND_List_Check ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + /* On vérifie les liens entre les noeuds */ + + ND_List_Link_Check (Root, Nb_Detected, Nb_Corrected, Out); + + /* On vérifie les valeurs des noeuds */ + + ND_Value_Check (Root, Nb_Detected, Nb_Corrected, Out); +} + +/*------------------------------------------------------------------------------*/ +/* Function de vérification et correction des liens entre noeuds d'une liste */ +/*------------------------------------------------------------------------------*/ +void ND_List_Link_Check ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + NDT_Node * Node; + int LeftToRight_Node_Number = 0; + int RightToLeft_Node_Number = 0; + + /* + On commence à vérifier si l'on trouve le même nombre de noeuds + en parcourant la liste de droite à gauche, puis de gauche à droite + */ + + Node = Root->Head; + + while (Node) + { + LeftToRight_Node_Number++; + Node = Node->Right; + } + + Node = Root->Queue; + + while (Node) + { + RightToLeft_Node_Number++; + Node = Node->Left; + } + + /* Cas où tout est OK */ + + if (LeftToRight_Node_Number == Root->Node_Number && LeftToRight_Node_Number == RightToLeft_Node_Number) return; + + /* Cas où le nombre de noeuds n'a simplement pas été mis à jour au niveau de la racine */ + + if (LeftToRight_Node_Number == RightToLeft_Node_Number) + { + Root->Node_Number = LeftToRight_Node_Number; + fprintf (Out, "\t- number of node has been corrected on structure %p\n", Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + return; + } + + /* Cas où le parcours de gauche à droite est plus complet : il manque un lien 'Left' */ + + if (LeftToRight_Node_Number > RightToLeft_Node_Number) + { + Node = Root->Head; + + while (Node) + { + if (Node->Right && Node->Right->Left != Node) + { + fprintf (Out, "\t- link 'Left' has been corrected on node %p of structure %p\n", Node->Right, Root); + Node->Right->Left = Node; + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + if (!Node->Right && Node != Root->Queue) + { + fprintf (Out, "\t- link 'Queue' has been corrected on structure %p\n", Root); + Root->Queue = Node; + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + Node = Node->Right; + } + + if (Root->Node_Number != LeftToRight_Node_Number) + { + fprintf (Out, "\t- number of node has been corrected on structure %p\n", Root); + Root->Node_Number = LeftToRight_Node_Number; + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + return; + } + + /* Cas où le parcours de droite à gauche est plus complet : il manque un lien 'Right' */ + + if (RightToLeft_Node_Number> LeftToRight_Node_Number) + { + Node = Root->Queue; + + while (Node) + { + if (Node->Left && Node->Left->Right != Node) + { + fprintf (Out, "\t- link 'Right' has been corrected on node %p of list %p\n", Node->Left, Root); + Node->Left->Right = Node; + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + if (!Node->Left && Node != Root->Head) + { + fprintf (Out, "\t- link 'Head' has been corrected on the structure root %p\n", Root); + Root->Head = Node; + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + Node = Node->Left; + } + + if (Root->Node_Number != RightToLeft_Node_Number) + { + fprintf (Out, "\t- number of node has been corrected on structure %p\n", Root); + Root->Node_Number = RightToLeft_Node_Number; + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + } +} + +/*------------------------------------------------------------------------------*/ +/* Function de vérification des valeurs des noeuds d'une liste */ +/*------------------------------------------------------------------------------*/ +void ND_Value_Check ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + NDT_Node * Node, * Next_Node; + + /* Chaque noeud sans valeur est purement et simplement supprimé de la liste */ + + ND_Node_First_Get_I (Root, &Node); + + while (Node) + { + ND_Node_Next_Get_I (Node, &Next_Node); + + if (!Node->Value) + { + fprintf (Out, "\t- node %p has been removed from structure %p because no value is attached to it\n", Node, Root); + + ND_Node_Remove (Node); + + Node = Next_Node; + + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + else if (ND_Address_Check (Node->Value) != NDS_OK) + { + fprintf (Out, "\t- node %p has been removed from structure %p because its value cannot be accessed\n", Node, Root); + + ND_Node_Remove (Node); + + Node = Next_Node; + + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + else ND_Node_Next_Get (Node, &Node); + } +} + +/*------------------------------------------------------------------------------*/ +/* Function de vérification d'un arbre : */ +/*------------------------------------------------------------------------------*/ +void ND_Tree_Check ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + /* On vérifie les liens entre les noeuds */ + + ND_Tree_Link_Check (Root, Nb_Detected, Nb_Corrected, Out); + + /* On vérifie les valeurs attachées aux noeuds */ + + ND_Value_Check (Root, Nb_Detected, Nb_Corrected, Out); + + /* On met à jour les informations statistiques de la racine */ + + Root->Max_Depth = ND_Tree_MaxDepth_Get (Root->Head); + Root->Min_Depth = ND_Tree_MaxDepth_Get (Root->Head); +} + +/*------------------------------------------------------------------------------*/ +/* Function de vérification et correction des liens entre noeuds d'un arbre */ +/*------------------------------------------------------------------------------*/ +void ND_Tree_Link_Check ( NDT_Root * Root, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + /* On vérifie les liens 'Parent' et les liens 'Root' de chaque noeud */ + + if (Root->Head) + { + if (Root->Head->Root != Root) + { + Root->Head->Root = Root; + fprintf (Out, "\t- link 'Root' has been corrected on node %p of structure %p\n", Root->Head, Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + ND_Tree_Link_Recursive_Check (Root->Head, Nb_Detected, Nb_Corrected, Out); + } + + /* + On vérifie si le lien 'Save' contient un noeud (cela signifie + que la procédure ND_Node_Remove n'a pas été jusqu'à son terme). + */ + + if (Root->Save) + { + NDT_Node * Node; + + /* On attache le noeud contenu dans 'Save' à l'arbre s'il n'existe pas déjà */ + + if (ND_Node_Find (Root, &Node, Root->Save->Value, NULL) != NDS_OK) + { + ND_Node_Add (Root, Root->Save); + fprintf (Out, "\t- saved node %p has been restored to structure %p\n", Root->Save, Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + Root->Save = NULL; + } +} + +/*------------------------------ Recursive Kernel ------------------------------*/ + +void ND_Tree_Link_Recursive_Check ( NDT_Node * Node, int * Nb_Detected, int * Nb_Corrected, FILE * Out ) +{ + if (Node->Left) + { + if (Node->Left->Root != Node->Root) + { + Node->Left->Root = Node->Root; + fprintf (Out, "\t- link 'Root' has been corrected on node %p of structure %p\n", Node->Left, Node->Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + if (Node->Left->Parent != Node) + { + Node->Left->Parent = Node; + fprintf (Out, "\t- link 'Parent' has been corrected on node %p of structure %p\n", Node->Left, Node->Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + /* Appel récursif */ + + ND_Tree_Link_Recursive_Check (Node->Left, Nb_Detected, Nb_Corrected, Out); + } + + if (Node->Right) + { + if (Node->Right->Root != Node->Root) + { + Node->Right->Root = Node->Root; + fprintf (Out, "\t- link 'Root' has been corrected on node %p of structure %p\n", Node->Right, Node->Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + if (Node->Right->Parent != Node) + { + Node->Right->Parent = Node; + fprintf (Out, "\t- link 'Parent' has been corrected on node %p of structure %p\n", Node->Right, Node->Root); + (*Nb_Detected)++; + (*Nb_Corrected)++; + } + + /* Appel récursif */ + + ND_Tree_Link_Recursive_Check (Node->Right, Nb_Detected, Nb_Corrected, Out); + } +} + +/*------------------------------------------------------------------------------*/ +/* Vérifie qu'une adresse est valide */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Address_Check ( void * Address ) +{ + int test; + + Sig_Trapped = 0; + + /* On trappe les signaux SIGBUS et SIGSEGV */ + + signal (SIGBUS, ND_Signal_Trap); + signal (SIGSEGV, ND_Signal_Trap); + + /* On tente d'accéder à l'adresse fournie */ + + test = *((int *)Address); + + sigrelse (SIGBUS); + sigrelse (SIGSEGV); + + if (Sig_Trapped != 0) return NDS_KO; + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Trap d'un signal */ +/*------------------------------------------------------------------------------*/ +void ND_Signal_Trap ( int Sig_Num ) +{ + Sig_Trapped = Sig_Num; +} + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'erreur */ +/*------------------------------------------------------------------------------*/ +void ND_Error_Print ( void ) +{ + if (ND_stderr) fprintf (ND_stderr, "%s\n", ND_Error_Msg); +} diff --git a/lib/libnode.h b/lib/libnode.h new file mode 100644 index 0000000..cf547e0 --- /dev/null +++ b/lib/libnode.h @@ -0,0 +1,243 @@ +#include +#include +#include +#include +#include +#include + +#define HUGE_LONG 0xFFFFFFL + +#ifndef min +#define min(A,B) ((A > B) ? B : A) +#endif + +#ifndef max +#define max(A,B) ((A < B) ? B : A) +#endif + +/* Sortie standard des messages d'erreur */ + +FILE * ND_stderr; + +/* Table des symboles locale */ + +struct Symbol { + void * Ptr; + char * Name; + struct Symbol * Next; +} * Symbol_Table = NULL; + +NDT_Root * Tmp_Root; + +extern char * strdup (const char *); +extern int sigrelse (int sig); + +int Sig_Trapped; + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* Fonctions et procédures privées de la librairie (moyen niveau) */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager par défaut */ +/*------------------------------------------------------------------------------*/ +/* (I) va_list Arguments : Liste d'arguments contextuels */ +/*------------------------------------------------------------------------------*/ +NDT_Status Default_Manager (va_list Arguments); + +/*------------------------------------------------------------------------------*/ +/* Redéfinition de la fonction malloc() avec retour de type NDT_Status */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Malloc (size_t Size, void ** ptr, void * User); + +/*------------------------------------------------------------------------------*/ +/* Redéfinition de la fonction free() avec retour de type NDT_Status */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Free (void * ptr); + +/*------------------------------------------------------------------------------*/ +/* Création d'un noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : adresse de la racine pour laquelle on crée un noeud */ +/* (O) New_Node : adresse du pointeur sur le nouveau noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Alloc (NDT_Root * Root, NDT_Node ** New_Node); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : adresse de la racine dans laquelle on détruit un noeud */ +/* (I) Node : pointeur sur le noeud à détruire */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Node_Free (NDT_Root * Root, NDT_Node * Node); + +/*------------------------------------------------------------------------------*/ +/* Création de la racine d'une structure de données quelconque */ +/*------------------------------------------------------------------------------*/ +/* (O) New_Root : adresse du pointeur sur la nouvelle racine */ +/* (I) Type : type de la structure de données */ +/* (I) Allocater : pointeur vers la fonction d'allocation */ +/* (I) Desallocater : pointeur vers la fonction de désallocation */ +/* (I) Data : pointeur de données utiles à l'allocateur */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Root_Alloc (NDT_Root ** Root, NDT_DataStruct_Type Type, \ + const char * Allocator, const char * Desallocator, \ + void * Data); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une racine */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine à détruire */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Root_Free (NDT_Root * Root); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à une liste chaînée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste */ +/* (I) New_Node : pointeur sur le noeud à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Node_Add (NDT_Root * Root, NDT_Node * New_Node); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une nouvelle valeur à une liste */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste */ +/* (I) Value : pointeur sur la valeur à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Value_Add (NDT_Root * Root, void * Value); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à un arbre binaire */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'arbre */ +/* (I) Value : pointeur sur la valeur à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_Value_Add (NDT_Root * Root, void * Value); + +/*------------------------------------------------------------------------------*/ +/* Supprime le noeud d'une liste */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud à supprimer */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Node_Remove (NDT_Node * Node); + +/*------------------------------------------------------------------------------*/ +/* Conversion d'une structure en liste chaînée */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine du la structure à convertir */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Make (NDT_Root * Root); + +/*------------------------------------------------------------------------------*/ +/* Recherche une valeur dans une liste et retourne le noeud correspondant */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_List_Node_Find (NDT_Root * Root, void * Value, void * Data); + +/*------------------------------------------------------------------------------*/ +/* Recherche un noeud dans un arbre et retourne le pointeur sur le noeud */ +/*------------------------------------------------------------------------------*/ +NDT_Node * ND_Tree_Node_Find (NDT_Root * Root, void * Value, void * Data); + +/*------------------------------------------------------------------------------*/ +/* Conversion d'une structure en arbre binaire */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine du la structure à convertir */ +/* (I) Type : type du futur arbre */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_Make (NDT_Root * Root); + +/*------------------------------------------------------------------------------*/ +/* Equilibrage d'un arbre */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'arbre */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_Equalize (NDT_Root * Root); + +/*------------------------------------------------------------------------------*/ +/* Retourne la profondeur de la plus grande branche à partir d'un noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud */ +/*------------------------------------------------------------------------------*/ +long ND_Tree_MaxDepth_Get (NDT_Node * Node); + +/*------------------------------------------------------------------------------*/ +/* Retourne la profondeur de la plus petite branche à partir d'un noeud */ +/*------------------------------------------------------------------------------*/ +/* (I) Node : pointeur sur le noeud */ +/*------------------------------------------------------------------------------*/ +long ND_Tree_MinDepth_Get (NDT_Node * Node); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un noeud à un arbre binaire */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de l'arbre */ +/* (I) Node : pointeur sur le noeud à ajouter */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_Node_Add (NDT_Root * Root, NDT_Node * Node); + +/*------------------------------------------------------------------------------*/ +/* Ajoute tous les noeud d'une liste à un arbre */ +/*------------------------------------------------------------------------------*/ +/* (I) Tree_Root : pointeur sur la racine de l'arbre */ +/* (I) List_Root : pointeur sur la racine de la liste */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_Tree_List_Add (NDT_Root * Tree_Root, NDT_Root * List_Root); + +/*------------------------------------------------------------------------------*/ +/* Fonction de comparaison de noeuds (pour le quick sort) */ +/*------------------------------------------------------------------------------*/ +int ND_Node_Compare (void ** Node1, void ** Node2); + +/*------------------------------------------------------------------------------*/ +/* Ordonne une liste chaînée selon l'algorithme du tri à bulle */ +/*------------------------------------------------------------------------------*/ +/* (I) Root : pointeur sur la racine de la liste à trier */ +/*------------------------------------------------------------------------------*/ +NDT_Status ND_List_Sort (NDT_Root * Root); + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* Fonctions et procédures privées de la librairie (bas niveau) */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +void ND_List_Check (NDT_Root *, int *, int *, FILE *); + +void ND_List_Link_Check (NDT_Root *, int *, int *, FILE *); + +void ND_Value_Check (NDT_Root *, int *, int *, FILE *); + +void ND_Tree_Check (NDT_Root *, int *, int *, FILE *); + +void ND_Tree_Link_Check (NDT_Root *, int *, int *, FILE *); + +NDT_Status ND_List_Recursive_Make (NDT_Node *, NDT_Root *); + +NDT_Node * ND_Tree_Recursive_Make (long, long, NDT_Node *); + +void ND_Tree_Node_Recursive_Add (NDT_Root *, NDT_Node *, NDT_Node **, long , NDT_Node *); + +NDT_Node * ND_Tree_Node_First_Recursive_Get (NDT_Node * Node); + +NDT_Node * ND_Tree_Node_Last_Recursive_Get (NDT_Node * Node); + +NDT_Node * ND_Tree_Node_Recursive_Find (NDT_Node * Node, void * Value, void * Data); + +NDT_Node * ND_Tree_Parent_Next_Recursive_Get (NDT_Node * Node); + +NDT_Node * ND_Tree_Parent_Previous_Recursive_Get (NDT_Node * Node); + +void ND_Tree_Recursive_Print (NDT_Node * Node, long Depth, FILE *); + +void ND_Tree_Link_Recursive_Check (NDT_Node * Node, int *, int *, FILE *); + +void * ND_Symbol_Find (const char *); + +void ND_Error_Print (void); + +void ND_Signal_Trap (int); + +NDT_Status ND_Address_Check (void * Address); diff --git a/util/ndbench.c b/util/ndbench.c new file mode 100644 index 0000000..70ae635 --- /dev/null +++ b/util/ndbench.c @@ -0,0 +1,469 @@ +#include +#include +#include +#include +#include + +#define ND_MODE 1 +#include + +VER_INFO_EXPORT (ndbench, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +#define USAGE "Usage : %s [ --help | --version [-v] ]\n" + +#define QUIT 0 +#define ADD_VALUE 1 +#define REMOVE_VALUE 2 +#define FIND_VALUE 3 +#define CHG_LIST_TYPE 4 +#define CONVERT_TO_TREE 5 +#define CONVERT_TO_LIST 6 +#define REORG 7 +#define INFO 8 +#define SHOW 9 +#define CHECK 10 + +char menu [1000]; +char buf [100]; +NDT_Root * Root; +long int random (void); +NDT_Status Module_Manager (va_list); +void init_menu (void); +int print_menu (void); +extern char * strdup (const char *); + +/* Mesure des temps d'exécution */ + +typedef struct { + double sec; + struct timeval start; + struct timeval stop; +} cpt; + +#define t_start(x){ gettimeofday (&(x.start), NULL);} +#define t_stop(x){ gettimeofday (&(x.stop), NULL); x.sec = (double)(x.stop.tv_sec) - (double)(x.start.tv_sec) + ((double)(x.stop.tv_usec) - (double)(x.start.tv_usec)) / 1000000;} +cpt t_exec; + +/* Définition des valeurs attachées aux noeuds de la structure */ + +typedef struct { + int Id; + char * Nom; +} T_Module; + +int main (int argc, char ** argv) +{ + char * tmp; + int n, m, i, j, choice, nb_removed, Nb_Detected, Nb_Corrected; + T_Module Ref_Module, * Module; + int Debug = TRUE; + + /* Lancement de commande en mode batch */ + + if (argc >= 2) + { + if (!strcmp (argv[1], "--help")) + { + fprintf (stderr, USAGE, argv[0]); + return 1; + } + else if (!strcmp (argv[1], "--version")) + { + if (argc >= 3 && !strcmp (argv[2], "-v")) + return VER_Object_Print (stdout, VERD_VERBOSE); + else + return VER_Object_Print (stdout, VERD_MINIMAL); + } + else + { + fprintf (stderr, USAGE, argv[0]); + return 0; + } + } + + /* Lancement du menu intercatif */ + + ND_Library_Open (Debug); + + printf ("\nCréation d'une structure de type liste FIFO...\n"); + ND_DataStruct_Open (&Root, NDD_DS_LIST | NDD_MN_FIFO, NULL, NULL, NULL, TRUE); + + strcpy (Root->Manager, "Module_Manager"); + + choice = print_menu (); + + while (choice != QUIT) + { + switch (choice) + { + case FIND_VALUE: + fprintf (stdout, "\nPlage de recherche (?->?) : "); + gets (buf); + tmp = strstr (buf, "->"); + if (tmp != NULL) + { + *tmp = '\0'; + n = atoi (buf); + tmp++; + tmp++; + m = atoi (tmp); + if (m < n) + { + printf ("\nEntrées non valides\n"); + break; + } + } + else + { + printf ("\nEntrées non valides\n"); + break; + } + + i = n; + j = m + 1; + t_start (t_exec); + while (i < j) + { + NDT_Node *Node; + Ref_Module.Id = n + (random () % m); + ND_Node_Find (Root, &Node, &Ref_Module, NULL); + i++; + } + t_stop (t_exec); + + fprintf (stdout, "\n%d valeur(s) recherchée(s) en %.4f sec (%.2f select/sec)\n",\ + m - n + 1, t_exec.sec, (m - n + 1) / t_exec.sec ); + break; + + + case ADD_VALUE: + fprintf (stdout, "\nPlage des valeurs à ajouter (?->?) : "); + gets (buf); + tmp = strstr (buf, "->"); + if (tmp != NULL) + { + *tmp = '\0'; + n = atoi (buf); + tmp++; + tmp++; + m = atoi (tmp); + if (m < n) + { + printf ("\nEntrées non valides\n"); + break; + } + } + else + { + printf ("\nEntrées non valides\n"); + break; + } + + fprintf (stdout, "\nOrdre d'ajout (croissant=0 décroissant=1) ? "); + gets (buf); + choice = atoi (buf); + if (choice == 0) + { + i = n; + j = m + 1; + t_start (t_exec); + while (i < j) + { + if (ND_Value_Alloc (Root, (void **)&Module, "x", i) == NDS_OK) + ND_Value_Add (Root, Module); + i++; + } + t_stop (t_exec); + } + else + { + i = m; + j = n - 1; + t_start (t_exec); + while (i > j) + { + if (ND_Value_Alloc (Root, (void **)&Module, "x", i) == NDS_OK) + ND_Value_Add (Root, Module); + i--; + } + t_stop (t_exec); + } + fprintf (stdout, "\n%d valeur(s) ajoutée(s) en %.4f sec (%.2f ajouts/sec)\n", \ + m - n + 1, t_exec.sec, (m - n + 1) / t_exec.sec ); + break; + + case REMOVE_VALUE: + nb_removed = 0; + fprintf (stdout, "\nPlage des valeurs à supprimer (?->?) : "); + gets (buf); + tmp = strstr (buf, "->"); + if (tmp != NULL) + { + *tmp = '\0'; + n = atoi (buf); + tmp++; + tmp++; + m = atoi (tmp); + if (m < n) + { + printf ("\nEntrées non valides\n"); + break; + } + } + else + { + printf ("\nEntrées non valides\n"); + break; + } + + fprintf (stdout, "\nOrdre de suppression (croissant=0 décroissant=1) ? "); + gets (buf); + choice = atoi (buf); + if (choice == 0) + { + i = n; + j = m + 1; + t_start (t_exec); + while (i < j) + { + Ref_Module.Id = i; + if (ND_Value_Remove (Root, &Ref_Module, (void **)&Module) == NDS_OK) + { + nb_removed++; + ND_Value_Free (Root, Module); + } + i++; + } + t_stop (t_exec); + } + else + { + i = m; + j = n - 1; + t_start (t_exec); + while (i > j) + { + Ref_Module.Id = i; + if (ND_Value_Remove (Root, &Ref_Module, (void **)&Module) == NDS_OK) + { + nb_removed++; + ND_Value_Free (Root, Module); + } + i--; + } + t_stop (t_exec); + } + fprintf (stdout, "\n%d valeur(s) supprimée(s) en %.4f sec (%.2f suppressions/sec)\n", \ + m - n + 1, t_exec.sec, (m - n + 1) / t_exec.sec ); + break; + + case CHG_LIST_TYPE: + fprintf (stdout, "\nType de liste (FIFO=0 ; FILO=1 ; triée=2) ? "); + gets (buf); + choice = atoi (buf); + switch (choice) + { + case 0: + Root->Type = NDD_DS_LIST | NDD_MN_FIFO; + break; + + case 1: + Root->Type = NDD_DS_LIST | NDD_MN_FILO; + break; + + case 2: + Root->Type = NDD_DS_LIST | NDD_MN_ORDERED; + break; + + default: + printf ("\nChoix non valide\n"); + break; + } + break; + + case REORG: + t_start (t_exec); + ND_DataStruct_Reorg (Root); + t_stop (t_exec); + fprintf (stdout, "\nRéorganisation de la structure en %.4f sec\n", t_exec.sec); + break; + + case CONVERT_TO_LIST: + t_start (t_exec); + ND_DataStruct_Convert (Root, NDD_DS_LIST | NDD_MN_ORDERED); + t_stop (t_exec); + fprintf (stdout, "\nConversion arbre vers liste en %.4f sec\n", t_exec.sec); + break; + + case CONVERT_TO_TREE: + t_start (t_exec); + ND_DataStruct_Convert (Root, NDD_DS_TREE | NDD_MN_AUTO_EQU); + t_stop (t_exec); + fprintf (stdout, "\nConversion liste vers arbre en %.4f sec\n", t_exec.sec); + break; + + case INFO: + ND_DataStruct_Info_Print (Root, stdout); + break; + + case SHOW: + ND_DataStruct_Dump (Root, stdout); + break; + + case CHECK: + Nb_Corrected = Nb_Detected = 0; + ND_DataStruct_Check (Root, &Nb_Detected, &Nb_Corrected, stderr); + break; + + default: + fprintf (stdout, "\nChoix %d non défini\n", choice); + + } + + choice = print_menu (); + } + + fprintf (stdout, "\nDestruction de la structure... "); + printf ("%s\n\n", (ND_DataStruct_Close (Root) == NDS_OK ? "OK" : "NOK")); + + ND_Library_Close (); + return 0; +} + +NDT_Status Module_Manager (va_list args_ptr) +{ + NDT_Command Command = (NDT_Command)va_arg (args_ptr, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Current_Root = va_arg (args_ptr, NDT_Root *); + T_Module ** Module = va_arg (args_ptr, T_Module **); + va_list Args = va_arg (args_ptr, va_list); + char * Nom = va_arg (Args, char *); + int Id = va_arg (Args, int); + + *Module = (T_Module *)malloc (sizeof (T_Module)); + (*Module)->Nom = strdup (Nom); + (*Module)->Id = Id; + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + T_Module * Module = (T_Module *)va_arg (args_ptr, void *); + FILE * Out = va_arg (args_ptr, FILE *); + + fprintf (Out, "Id=%d\tNom=\"%s\"", Module->Id, Module->Nom); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Current_Root = va_arg (args_ptr, NDT_Root *); + T_Module * Module = (T_Module *)va_arg (args_ptr, void *); + + free (Module->Nom); + free (Module); + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Current_Root = va_arg (args_ptr, NDT_Root *); + FILE * Out = va_arg (args_ptr, FILE *); + char Root_Type[100]; + + switch ((int) (Current_Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int) (Current_Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : strcpy (Root_Type, "liste triée"); break; + case NDD_MN_FILO : strcpy (Root_Type, "liste FILO"); break; + case NDD_MN_FIFO : strcpy (Root_Type, "liste FIFO"); break; + default: strcpy (Root_Type, "inconnu"); break; + } + break; + + case NDD_DS_TREE : + + switch ((int) (Current_Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : strcpy (Root_Type, "arbre auto-équilibré"); break; + default: strcpy (Root_Type, "arbre non auto-équilibré"); break; + } + break; + + default: strcpy (Root_Type, "inconnu"); break; + + } + + fprintf (Out, "\nStructure de type %s :\n\t- Nombre de noeuds = %ld\n", Root_Type, Current_Root->Node_Number); + + if ((Current_Root->Type & NDD_DS_MSK) == NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", \ + Current_Root->Max_Depth, Current_Root->Min_Depth, Current_Root->Max_Dif, Current_Root->Nb_Equ); + + return (NDS_OK); + } + + if (Command == NDD_CMD_COMP_VALUE) + { + T_Module * Value1, * Value2; + long comp; + + Value1 = (T_Module *)va_arg (args_ptr, void *); + Value2 = (T_Module *)va_arg (args_ptr, void *); + va_end (args_ptr); + comp = Value1->Id - Value2->Id; + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + va_end (args_ptr); + return (NDS_OK); +} + +void init_menu (void) +{ + sprintf (menu, "Menu :\n"); + sprintf (buf, "\t- %d) %-30s\n", QUIT, "Quitter"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s", ADD_VALUE, "Ajout de valeurs"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s\n", REMOVE_VALUE, "Suppression de valeurs"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s\n", FIND_VALUE, "Recherche de valeurs aléatoires"); strcat (menu, buf); + if (ND_IS_LIST(Root)) + { + sprintf (buf, "\t- %d) %-30s", CHG_LIST_TYPE, "Changement de type de liste"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s\n", CONVERT_TO_TREE, "Conversion en arbre"); strcat (menu, buf); + } + else + { + sprintf (buf, "\t- %d) %-30s\n", CONVERT_TO_LIST, "Conversion en liste triée"); strcat (menu, buf); + } + + sprintf (buf, "\t- %d) %-30s\n", REORG, "Réorganisation"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s", INFO, "Informations sur la structure"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s\n", SHOW, "Affichage de la structure"); strcat (menu, buf); + sprintf (buf, "\t- %d) %-30s\n", CHECK, "Vérification de la structure"); strcat (menu, buf); +} + +int print_menu (void) +{ + int choice; + + init_menu (); + fprintf (stdout, "\n-----------------------------------------------------------------------\n"); + fprintf (stdout, menu); + *buf = (char)0; + while (!*buf) + { + printf ("\nChoice ? "); + gets (buf); + } + choice = atoi (buf); + + return choice; +} diff --git a/util/ndbench.xls b/util/ndbench.xls new file mode 100644 index 0000000..b80ce7c Binary files /dev/null and b/util/ndbench.xls differ