/*************************************************************************\ * Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * SPDX-License-Identifier: EPICS * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* * Author: John Winans (ANL) * Date: 07-02-92 */ #include #include "epicsAssert.h" #include "ellLib.h" /**************************************************************************** * * This function adds a node to the end of a linked list. * *****************************************************************************/ void ellAdd (ELLLIST *pList, ELLNODE *pNode) { pNode->next = NULL; pNode->previous = pList->node.previous; if (pList->count) pList->node.previous->next = pNode; else pList->node.next = pNode; pList->node.previous = pNode; pList->count++; } /**************************************************************************** * * This function concatenates the second linked list to the end of the first * list. The second list is left empty. Either list (or both) lists may * be empty at the beginning of the operation. * *****************************************************************************/ void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList) { if (pAddList->count == 0) return; /* Add list is empty, nothing to add. */ if (pDstList->count == 0) { /* Destination list is empty... just transfer the add list over. */ pDstList->node.next = pAddList->node.next; pDstList->node.previous = pAddList->node.previous; pDstList->count = pAddList->count; } else { /* Destination list not empty... append the add list. */ pDstList->node.previous->next = pAddList->node.next; pAddList->node.next->previous = pDstList->node.previous; pDstList->node.previous = pAddList->node.previous; pDstList->count += pAddList->count; } pAddList->count = 0; pAddList->node.next = NULL; pAddList->node.previous = NULL; } /**************************************************************************** * * This function deletes a specific node from a specified list; * *****************************************************************************/ void ellDelete (ELLLIST *pList, ELLNODE *pNode) { if (pList->node.previous == pNode) pList->node.previous = pNode->previous; else pNode->next->previous = pNode->previous; if (pList->node.next == pNode) pList->node.next = pNode->next; else pNode->previous->next = pNode->next; pList->count--; } /**************************************************************************** * * This function extracts a sublist that starts with pStartNode and ends with * pEndNode from pSrcList and places it in pDstList. * * WRS is unclear as to what happens when pDstList is non-empty at the start * of the operation. We will place the extracted list at the END of pDstList * when it is non-empty. * *****************************************************************************/ void ellExtract (ELLLIST *pSrcList, ELLNODE *pStartNode, ELLNODE *pEndNode, ELLLIST *pDstList) { ELLNODE *pnode; int count; /* Cut the list out of the source list (update count later) */ if (pStartNode->previous != NULL) pStartNode->previous->next = pEndNode->next; else pSrcList->node.next = pEndNode->next; if (pEndNode->next != NULL) { pEndNode->next->previous = pStartNode->previous; pEndNode->next = NULL; } else pSrcList->node.previous = pStartNode->previous; /* Place the sublist into the destination list */ pStartNode->previous = pDstList->node.previous; if (pDstList->count) pDstList->node.previous->next = pStartNode; else pDstList->node.next = pStartNode; pDstList->node.previous = pEndNode; /* Adjust the counts */ pnode = pStartNode; count = 1; while(pnode != pEndNode) { pnode = pnode->next; count++; } pSrcList->count -= count; pDstList->count += count; } /**************************************************************************** * * This function returns the first node in the specified list. The node is * removed from the list. If the list is empty, NULL will be returned. * *****************************************************************************/ ELLNODE * ellGet (ELLLIST *pList) { ELLNODE *pnode = pList->node.next; if (pnode != NULL) ellDelete(pList, pnode); return pnode; } /**************************************************************************** * * This function returns the last node in the specified list. The node is * removed from the list. If the list is empty, NULL will be returned. * *****************************************************************************/ ELLNODE * ellPop (ELLLIST *pList) { ELLNODE *pnode = pList->node.previous; if (pnode != NULL) ellDelete(pList, pnode); return pnode; } /**************************************************************************** * * This function inserts the specified node pNode after pPrev in the list * plist. If pPrev is NULL, then pNode will be inserted at the head of the * list. * *****************************************************************************/ void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode) { if (pPrev != NULL) { pNode->previous = pPrev; pNode->next = pPrev->next; pPrev->next = pNode; } else { pNode->previous = NULL; pNode->next = plist->node.next; plist->node.next = pNode; } if (pNode->next == NULL) plist->node.previous = pNode; else pNode->next->previous = pNode; plist->count++; } /**************************************************************************** * * This function returns the nodeNum'th element in pList. If there is no * nodeNum'th node in the list, NULL will be returned. * *****************************************************************************/ ELLNODE * ellNth (ELLLIST *pList, int nodeNum) { ELLNODE *pnode; if ((nodeNum < 1) || (pList->count == 0)) return NULL; if (nodeNum > pList->count/2) { if (nodeNum > pList->count) return NULL; pnode = pList->node.previous; nodeNum = pList->count - nodeNum; while(nodeNum) { pnode = pnode->previous; nodeNum--; } return pnode; } pnode = pList->node.next; while (--nodeNum > 0) pnode = pnode->next; return pnode; } /**************************************************************************** * * This function returns the node, nStep nodes forward from pNode. If there is * no node that many steps from pNode, NULL will be returned. * *****************************************************************************/ ELLNODE * ellNStep (ELLNODE *pNode, int nStep) { if (nStep > 0) { while ((pNode != NULL) && nStep) { pNode = pNode->next; nStep--; } } else { while ((pNode != NULL) && nStep) { pNode = pNode->previous; nStep++; } } return pNode; } /**************************************************************************** * * This function returns the node number of pNode within pList. If the node is * not in pList, -1 is returned. Note that the first node is 1. * *****************************************************************************/ int ellFind (ELLLIST *pList, ELLNODE *pNode) { ELLNODE *got = pList->node.next; int count = 1; while ((got != pNode) && (got != NULL)) { got = got->next; count++; } if (got == NULL) return -1; return count; } /**************************************************************************** * * This function frees the nodes in a list. It makes the list into an empty * list, and calls freeFunc() for all the nodes that are (were) in that list. * * NOTE: the nodes in the list are free()'d on the assumption that the node * structures were malloc()'d one-at-a-time and that the ELLNODE structure is * the first member of the parent structure. * *****************************************************************************/ void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc) { ELLNODE *nnode = pList->node.next; ELLNODE *pnode; while (nnode != NULL) { pnode = nnode; nnode = nnode->next; freeFunc(pnode); } pList->node.next = NULL; pList->node.previous = NULL; pList->count = 0; } /**************************************************************************** * * This function verifies that the list is consistent. * joh 12-12-97 * *****************************************************************************/ void ellVerify (ELLLIST *pList) { ELLNODE *pNode; ELLNODE *pNext; int count = 0; assert (pList); pNode = ellFirst(pList); if (pNode) { assert (ellPrevious(pNode) == NULL); while (1) { count++; pNext = ellNext(pNode); if (pNext) { assert (ellPrevious(pNext) == pNode); } else { break; } pNode = pNext; } assert (ellNext(pNode) == NULL); } assert (pNode == ellLast(pList)); assert (count == ellCount(pList)); }