/*------------------------------------------------------------------- | Return the length of the object identified by the cursor Curs -------------------------------------------------------------------*/ int APIENTRY List_ItemLength( LPVOID Curs ) { LIST pit; if (Curs==NULL) { TRACE_ERROR("Bug: List_ItemLength NULL cursor. Continuing...", FALSE); return 0; } MOVEBACK(Curs) pit = (LIST)Curs; return pit->iLen; }
/*----------------------------------------------------------------------- | Let L1 be *pl1 and L2 be *pl2 | L1 := L1[...Curs] || L2 || L1[Curs+1...]; L2 := empty | Curs=NULL means insert L2 at the start of L1 | The elements themselves are not moved, so pointers to them remain valid. | | L1 gets the elements of L1 from the start up to and including the element | that Curs points at, in their original order, | followed by all the elements that were in L2, in their original order, | followed by the rest of L1 ------------------------------------------------------------------------*/ void APIENTRY List_InsertListAfter( LIST l1, LIST l2, LPVOID Curs ) { LIST pitA; /* The element after Curs, could be anchor */ LIST pit; /* The start of the element that Curs points at | or the anchor block if Curs==NULL */ if ( (l1==NULL) || (l2==NULL)) { TRACE_ERROR("Bug: List_InsertListAfter with bogus list. Continuing...", FALSE); return; } l1->bOK = l1->bOK && l2->bOK; l2->bOK = TRUE; if (l2->pitNext==l2) { /* no elements need moving */ } else if ( l1->pitNext==l1) { /* the easy way to code this would be simply to switch the two | pointers l1 and l2, but they are value parameters and we don't | want to change that. */ SwitchLists(l1,l2); return; } else { if (Curs==NULL) { pit = l1; } else { MOVEBACK(Curs) pit = (LIST)Curs; } /* pit points to a block to insert after, could be anchor */ pitA = pit->pitNext; /* Cannot be same as P, already checked */ l2->pitNext->pitPrev = pit; /* P<-- elems-of-l2 A */ l2->pitPrev->pitNext = pitA; /* P<-- elems-of-l2 -->A */ pit->pitNext = l2->pitNext; /* P<-->elems-of-l2 -->A */ pitA->pitPrev = l2->pitPrev; /* P<-->elems-of-l2<-->A */ l2->pitNext = l2; l2->pitPrev = l2; } }
/*------------------------------------------------------------------ | Delete the item that Curs identifies. | This will be only a few (maybe as little as 3) machine instructions | quicker than DeleteForwards or DeleteBackwards but leaves Curs dangling. | It is therefore NOT usually to be preferred. | It may be useful when you have a function which returns an LPVOID | since the argument does not need to be a variable. | Trivial example: List_Delete(List_First(L)); -------------------------------------------------------------------*/ void APIENTRY List_Delete( LPVOID Curs ) { LIST pit; if (Curs==NULL) { TRACE_ERROR("Bug: List_Delete NULL item", FALSE); return; } MOVEBACK(Curs) pit = (LIST)Curs; pit->pitNext->pitPrev = pit->pitPrev; pit->pitPrev->pitNext = pit->pitNext; list_Free(pit->pBlock, pit); }
/*------------------------------------------------------------------ | Return the address of the object after Curs^. | List_Prev(List_First(L)) == NULL; List_Prev(NULL) is an error. -------------------------------------------------------------------*/ LPVOID APIENTRY List_Prev( LPVOID Curs ) { LIST pit; if (Curs==NULL) { TRACE_ERROR("Bug: List_Prev of NULL cursor. Continuing...", FALSE); return NULL; } MOVEBACK(Curs) pit = (LIST)Curs; pit = pit->pitPrev; if (pit->bAnchor) { return NULL; } else { return &(pit->Data); } }
/*----------------------------------------------------------------------- | Let l1 be l1 and l2 be l2 | Split l2 off from the front of l1: final l2,l1 = original l1 | | Split l1 into l2: objects of l1 up to and including Curs object | l1: objects of l1 after Curs | Any original contents of l2 are freed. | List_Spilt(l1, l2, NULL) splits l1 before the first object so l1 gets all. | The elements themselves are not moved. ------------------------------------------------------------------------*/ void APIENTRY List_SplitAfter( LIST l1, LIST l2, LPVOID Curs ) { LIST pit; if ((l1==NULL) || (l2==NULL)) { TRACE_ERROR("Bug: List_SplitAfter bogus list. Continuing...", FALSE); return; } if (l2->pitNext!=l2) { List_Clear(l2); }; if (Curs!=NULL) { MOVEBACK(Curs) pit = (LIST)Curs; /* Curs had better be an item in l1! l2 had better be created! */ if (pit==l1) { l1->bOK = FALSE; l2->bOK = FALSE; return; } if (pit->pitNext==l1) { /* transfer whole of l2 to l1 */ SwitchLists(l2,l1); return; } l2->pitPrev = pit; l2->pitNext = l1->pitNext; l1->pitNext = pit->pitNext; pit->pitNext = l2; l2->pitNext->pitPrev = l2; l1->pitNext->pitPrev = l1; } }
/*---------------------------------------------------------------------- | Split l2 off from the back of l1: final l1,l2 = original l1 | | Split l1 into l1: objects of l1 up to but not including Curs object | l2: objects of l1 from Curs onwards | Any original contants of l2 are freed. | List_Spilt(l1, l2, NULL) splits l1 after the last object so l1 gets all. | The elements themselves are not moved. -----------------------------------------------------------------------*/ void APIENTRY List_SplitBefore( LIST l1, LIST l2, LPVOID Curs ) { LIST pit; if ((l1==NULL) || (l2==NULL)) { TRACE_ERROR("Bug: List_SplitBefore bogus list. Continuing...", FALSE); return; } if (l2->pitNext!=l2) { List_Clear(l2); } if (Curs!=NULL) { MOVEBACK(Curs) pit = (LIST)Curs; /* Curs had better be an item in L1! L2 had better be created! */ if (pit==l1) { l1->bOK = FALSE; l2->bOK = FALSE; return; } if (pit->pitPrev==l1) { SwitchLists(l2,l1); return; } l2->pitNext = pit; l2->pitPrev = l1->pitPrev; l1->pitPrev = pit->pitPrev; pit->pitPrev = l2; l2->pitPrev->pitNext = l2; l1->pitPrev->pitNext = l1; } }
/*-------------------------------------------------------------------- | Add an item holding Object to lst immediately before Curs. | List_AddBefore(Lst,NULL,Object,uLen) adds it to the end of the list ---------------------------------------------------------------------*/ void APIENTRY List_AddBefore( LIST lst, LPVOID Curs, LPVOID pObject, UINT uLen ) { LIST pitNew; LIST pitBefore; if (lst==NULL) { TRACE_ERROR("Bug: List_AddBefore in bogus list. Continuing...", FALSE); return; } if (Curs==NULL) { List_AddLast(lst, pObject, uLen); } else { MOVEBACK(Curs); pitBefore = (LIST)Curs; pitNew = (LIST)list_Alloc(iHeaderSize+uLen); if (pitNew==NULL) { lst->bOK = FALSE; return; } pitNew->pBlock = pCurrent; LeaveCriticalSection(&CritSec); pitNew->iLen = uLen; pitNew->pitNext = pitBefore; pitNew->pitPrev = pitBefore->pitPrev; pitBefore->pitPrev->pitNext = pitNew; pitBefore->pitPrev = pitNew; pitNew->bAnchor = FALSE; memcpy( &(pitNew->Data), pObject, uLen ); } }
/*----------------------------------------------------------------------- | Delete the item that Curs identifies and return a cursor that | identifies the previous item (NULL if already on first) ------------------------------------------------------------------------*/ LPVOID APIENTRY List_DeleteBackwards( LPVOID Curs ) { LIST pitDel; /* the one to delete */ LIST pitB; /* the one before */ if (Curs==NULL) { TRACE_ERROR("List_DeleteBackwards NULL cursor. Continuing...", FALSE); return NULL; } MOVEBACK(Curs) pitDel = (LIST)Curs; pitB = pitDel->pitPrev; pitDel->pitNext->pitPrev = pitB; pitB->pitNext = pitDel->pitNext; list_Free(pitDel->pBlock, pitDel); if (pitB->bAnchor) return NULL; else return (char *)&(pitB->Data); }
/*----------------------------------------------------------------------- | Delete the item that Curs identifies and return a cursor that | identifies the next item (NULL if already on last) ------------------------------------------------------------------------*/ LPVOID APIENTRY List_DeleteForwards( LPVOID Curs ) { LIST pitDel; /* the item to delete */ LIST pitN; /* the item after (could be anchor) */ if (Curs==NULL) { TRACE_ERROR("Bug: List_DeleteForwards NULL cursor. Continuing...", FALSE); return NULL; } MOVEBACK(Curs) pitDel = (LIST)Curs; pitN = pitDel->pitNext; pitN->pitPrev = pitDel->pitPrev; pitDel->pitPrev->pitNext = pitN; list_Free(pitDel->pBlock, pitDel); if (pitN->bAnchor) return NULL; else return (char *)&(pitN->Data); }
/*-------------------------------------------------------------------- | Return the address of the place for uLen bytes of data in a new | item immediately after Curs. | List_NewAfter(Lst,NULL,uLen) returns a pointer | to space for uLen bytes in a new first element. ---------------------------------------------------------------------*/ LPVOID APIENTRY List_NewAfter( LIST lst, LPVOID Curs, UINT uLen ) { LIST pitNew; LIST pitAfter; if (lst==NULL) { TRACE_ERROR("Bug: List_NewAfter in bogus list. Continuing...", FALSE); return NULL; } if (Curs==NULL) { return List_NewFirst(lst, uLen); } else { MOVEBACK(Curs); pitAfter = (LIST)Curs; pitNew = (LIST)list_Alloc(iHeaderSize+uLen); if (pitNew==NULL) { lst->bOK = FALSE; return NULL; } pitNew->pBlock = pCurrent; LeaveCriticalSection(&CritSec); pitNew->iLen = uLen; pitNew->pitPrev = pitAfter; pitNew->pitNext = pitAfter->pitNext; pitAfter->pitNext->pitPrev = pitNew; pitAfter->pitNext = pitNew; pitNew->bAnchor = FALSE; return (char *)&(pitNew->Data); } }