From 6fe492faf6cd397b06f01c2c9305e310c88ee290 Mon Sep 17 00:00:00 2001 From: smas Date: Tue, 18 Jul 2000 14:51:56 +0000 Subject: [PATCH] First stable version LINUX / SOLARIS compatible. --- doc/libnode.doc | Bin 0 -> 112640 bytes doc/man3/libnode.3 | 947 ++++++++++++++++ include/node.h | 461 ++++++++ lib/libnode.c | 2674 ++++++++++++++++++++++++++++++++++++++++++++ lib/libnode.h | 243 ++++ util/ndbench.c | 469 ++++++++ util/ndbench.xls | Bin 0 -> 16896 bytes 7 files changed, 4794 insertions(+) create mode 100644 doc/libnode.doc create mode 100644 doc/man3/libnode.3 create mode 100644 include/node.h create mode 100644 lib/libnode.c create mode 100644 lib/libnode.h create mode 100644 util/ndbench.c create mode 100644 util/ndbench.xls diff --git a/doc/libnode.doc b/doc/libnode.doc new file mode 100644 index 0000000000000000000000000000000000000000..92a1947ade9c9d8a5d8ed2c5d586f81bdc9fc748 GIT binary patch literal 112640 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
Swz|yDv2$~CH(}&hJYS=XoEhVH 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 +.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 0000000000000000000000000000000000000000..b80ce7caf6dc3d9d5cab0c9620d0e5f394a2651b GIT binary patch literal 16896 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 literal 0 HcmV?d00001