/** \file * \brief Type safe list handling * * The definition and implementation make use of macros extensively to create * a list type and related functions for any node type. * However, accessing the list does not use macros. * The list is implemented as a singly linked list. Sequential appending * to the tail is fast, because the list structure contains * a pointer to the anchor of the last accessed node. * * For a local list, mclist.c must be included after * the declaration of the node type and after defining the macro MC_NAME * and optionally MC_TYPE and MC_NEXT. * * For a public list, in the header file mclist.h must be included after * the declaration of the node type and after defining the macro MC_NAME * and optionally MC_TYPE. In the implementation mclist.c * must be included after defining the macro MC_NAME and MC_IMPLEMENTATION * and optionally MC_TYPE and MC_NEXT. * * MC_NAME has one parameter and describes how to combine the list name * with the function names. * * MC_TYPE defines the node type. If undeclared it defaults to a pointer * to the name. * * MC_NEXT indicates the name of the link. It defaults to 'next'. * * MC_IMPLEMENTATION has no value and must be defined when the list type * was already declared. Typically this is done in a header file including mclist.h. * * The macros MC_NAME, MC_TYPE, MC_NEXT and MC_IMPLEMENTATION are undefined * within mclist.c and mclist.h and must be redefined for every list. * * \par Usage example * \code * // declare the Node type * typedef struct Node { * struct Node *next; * char *name; * } Node; * * // this declaration leads to a list type 'NodeList' and fucntions names 'Node' * #define MC_NAME(T) Node##T * // the following line is not needed as 'next' is the default for the link * #define MC_NEXT next * // the following line is not needed as 'Node *' is the default for the type in this case * #define MC_TYPE Node * * // inside mclist.c, the list type is declared and the related functions are implemented * #include "mclist.c" * * int main(void) { * // declare and init the list * NodeList list={NULL}; * * // create a node * Node *node; * node = malloc(sizeof(*node)); * node->name = "First"; * * // add node at the end of the list * NodeAdd(&list, node); * * // print the names of all list nodes * for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) { * printf("%s\n", node->name); * } * * // alternative form not touching the list position * // only for the case, where no insert or take function is used inside the loop * for (node = list.head; node != NULL; node = node->next) { * printf("%s\n", node->name); * } * * // remove the node with the name "First" * for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) { * if (strcmp(node->name, "First") == 0) { * free(NodeTake(&list)); * } * } * } * \endcode */ #ifndef MC_TYPE /** \brief default node type */ #define MC_TYPE MC_NAME()* #endif #ifndef MC_List_TYPE #define MC_List_TYPE MC_NAME(List) #define MC_First_FUN MC_NAME(First) #define MC_This_FUN MC_NAME(This) #define MC_Next_FUN MC_NAME(Next) #define MC_End_FUN MC_NAME(End) #define MC_Insert_FUN MC_NAME(Insert) #define MC_Add_FUN MC_NAME(Add) #define MC_Take_FUN MC_NAME(Take) #define MC_Delete_FUN MC_NAME(Delete) #endif typedef struct MC_List_TYPE { MC_TYPE head; MC_TYPE *ptr; } MC_List_TYPE; /** \brief move to first node and get it * \param list the list * \return the node or NULL when the list is empty * * Actual position on return: at the first node */ MC_TYPE MC_First_FUN(MC_List_TYPE * list); /** \brief get the node at the current position * \param list the list * \return the node or NULL when the list is empty or the position is at end * * Actual position on return: not changed (= at the returned node) */ MC_TYPE MC_This_FUN(MC_List_TYPE * list); /** \brief get the node after the current node * \param list the list * \return the node or NULL when the list is empty or the position is at end * * Actual position on return: incremented (= at the returned node or at end) */ MC_TYPE MC_Next_FUN(MC_List_TYPE * list); /** \brief move the position to the end * \param list the list * * Actual position on return: at end */ void MC_End_FUN(MC_List_TYPE * list); /** \brief insert at the current position, i.e. before the current node * \param list the list * \param node the node to be inserted * * Actual position on return: at the inserted node */ void MC_Insert_FUN(MC_List_TYPE * list, MC_TYPE node); /** \brief add at the end of the list * \param list the list * \param node the node to be added * * Actual position on return: at the inserted node (before the last node, not at end!) */ void MC_Add_FUN(MC_List_TYPE * list, MC_TYPE node); /** \brief remove the node at the current position * \param list the list * \return the removed node or NULL when the list is empty or the position is at end * * Actual position on return: after the taken node * * Note: it is the responsibility of the caller to free the node if it is not used * anymore */ MC_TYPE MC_Take_FUN(MC_List_TYPE * list); /** \brief remove and delete all nodes * \param list the list * \param deleteFunc the kill function of the node * * Calls the kill function for every node. The list is * empty on return. */ void MC_Delete_FUN(MC_List_TYPE * list, void (*deleteFunc) (MC_TYPE node)); #ifndef MC_DO_NOT_UNDEF #undef MC_NAME #undef MC_TYPE #endif