summaryrefslogtreecommitdiffstats
path: root/linkedlist.c
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-11-21 16:34:48 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-11-21 16:34:48 +0000
commit3bb7ad8246bca95c89d68a8b0402b8482489c877 (patch)
tree798656b4722649346cbd43a0a328041832666237 /linkedlist.c
parentbb6bfca3dfa6a5d3500e51459b38bb6d0ca6a4b2 (diff)
downloadrsyslog-3bb7ad8246bca95c89d68a8b0402b8482489c877.tar.gz
rsyslog-3bb7ad8246bca95c89d68a8b0402b8482489c877.tar.xz
rsyslog-3bb7ad8246bca95c89d68a8b0402b8482489c877.zip
- added an identifier to command handler table - need to identify which
command handler entries need to be removed when module is unloaded - added support so that linkedlist key can be used for owner handle - enhanced llExecFunc to support deletion of list elements (on behalf of user function being called, slight interface change) - enhanced linkedlist class so that list elements can now be deleted based on the key value they have - created entry point so that CfSysLine handlers are removed on modExit()
Diffstat (limited to 'linkedlist.c')
-rw-r--r--linkedlist.c120
1 files changed, 112 insertions, 8 deletions
diff --git a/linkedlist.c b/linkedlist.c
index b9239b48..bea2cb90 100644
--- a/linkedlist.c
+++ b/linkedlist.c
@@ -229,36 +229,124 @@ finalize_it:
}
-/* find a user element based on the provided key
+/* unlink a requested element. As we have singly-linked lists, the
+ * caller also needs to pass in the previous element (or NULL, if it is the
+ * root element).
+ * rgerhards, 2007-11-21
*/
-rsRetVal llFind(linkedList_t *pThis, void *pKey, void **ppData)
+static rsRetVal llUnlinkElt(linkedList_t *pThis, llElt_t *pElt, llElt_t *pEltPrev)
+{
+ assert(pElt != NULL);
+
+ if(pEltPrev == NULL) { /* root element? */
+ pThis->pRoot = pElt->pNext;
+ } else { /* regular element */
+ pEltPrev->pNext = pElt->pNext;
+ }
+
+ if(pElt == pThis->pLast)
+ pThis->pLast = pEltPrev;
+
+ return RS_RET_OK;
+}
+
+
+/* unlinks and immediately deletes an element. Previous element must
+ * be given (or zero if the root element is to be deleted).
+ * rgerhards, 2007-11-21
+ */
+static rsRetVal llUnlinkAndDelteElt(linkedList_t *pThis, llElt_t *pElt, llElt_t *pEltPrev)
+{
+ DEFiRet;
+
+ assert(pElt != NULL);
+
+ CHKiRet(llUnlinkElt(pThis, pElt, pEltPrev));
+ CHKiRet(llDestroyElt(pThis, pElt));
+
+finalize_it:
+ return iRet;
+}
+
+/* find a user element based on the provided key - this is the
+ * internal variant, which also tracks the last element pointer
+ * before the found element. This is necessary to delete elements.
+ * NULL means there is no element in front of it, aka the found elt
+ * is the root elt.
+ * rgerhards, 2007-11-21
+ */
+static rsRetVal llFindElt(linkedList_t *pThis, void *pKey, llElt_t **ppElt, llElt_t **ppEltPrev)
{
DEFiRet;
llElt_t *pElt;
+ llElt_t *pEltPrev = NULL;
int bFound = 0;
assert(pThis != NULL);
assert(pKey != NULL);
- assert(ppData != NULL);
+ assert(ppElt != NULL);
+ assert(ppEltPrev != NULL);
pElt = pThis->pRoot;
while(pElt != NULL && bFound == 0) {
if(pThis->cmpOp(pKey, pElt->pKey) == 0)
bFound = 1;
- else
+ else {
+ pEltPrev = pElt;
pElt = pElt->pNext;
+ }
}
if(bFound == 1) {
- *ppData = pElt->pData;
- } else {
+ *ppElt = pElt;
+ *ppEltPrev = pEltPrev;
+ } else
iRet = RS_RET_NOT_FOUND;
- }
return iRet;
}
+/* find a user element based on the provided key
+ */
+rsRetVal llFind(linkedList_t *pThis, void *pKey, void **ppData)
+{
+ DEFiRet;
+ llElt_t *pElt;
+ llElt_t *pEltPrev;
+
+ CHKiRet(llFindElt(pThis, pKey, &pElt, &pEltPrev));
+
+ /* if we reach this point, we have found the element */
+ *ppData = pElt->pData;
+
+finalize_it:
+ return iRet;
+}
+
+
+/* find a delete an element based on user-provided key. The element is
+ * delete, the caller does not receive anything. If we need to receive
+ * the element before destruction, we may implement an llFindAndUnlink()
+ * at that time.
+ * rgerhards, 2007-11-21
+ */
+rsRetVal llFindAndDelete(linkedList_t *pThis, void *pKey)
+{
+ DEFiRet;
+ llElt_t *pElt;
+ llElt_t *pEltPrev;
+
+ CHKiRet(llFindElt(pThis, pKey, &pElt, &pEltPrev));
+
+ /* if we reach this point, we have found an element */
+ CHKiRet(llUnlinkAndDelteElt(pThis, pElt, pEltPrev));
+
+finalize_it:
+ return iRet;
+}
+
+
/* provide the count of linked list elements
*/
rsRetVal llGetNumElts(linkedList_t *pThis, int *piCnt)
@@ -279,6 +367,9 @@ rsRetVal llGetNumElts(linkedList_t *pThis, int *piCnt)
* or a pointer to a structure with more data. If the user-supplied
* function does not return RS_RET_OK, this function here terminates.
* rgerhards, 2007-08-02
+ * rgerhards, 2007-11-21: added functionality to delete a list element.
+ * If the called user function returns RS_RET_OK_DELETE_LISTENTRY the current element
+ * is deleted.
*/
rsRetVal llExecFunc(linkedList_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam)
{
@@ -286,12 +377,25 @@ rsRetVal llExecFunc(linkedList_t *pThis, rsRetVal (*pFunc)(void*, void*), void*
rsRetVal iRetLL;
void *pData;
linkedListCookie_t llCookie = NULL;
+ linkedListCookie_t llCookiePrev = NULL; /* previous list element (needed for deletion, NULL = at root) */
assert(pThis != NULL);
assert(pFunc != NULL);
while((iRetLL = llGetNextElt(pThis, &llCookie, (void**)&pData)) == RS_RET_OK) {
- CHKiRet(pFunc(pData, pParam));
+ iRet = pFunc(pData, pParam);
+ if(iRet == RS_RET_OK_DELETE_LISTENTRY) {
+ /* delete element */
+ CHKiRet(llUnlinkAndDelteElt(pThis, llCookie, llCookiePrev));
+ /* we need to revert back, as we have just deleted the current element.
+ * So the actual current element is the one before it, which happens to be
+ * stored in llCookiePrev. -- rgerhards, 2007-11-21
+ */
+ llCookie = llCookiePrev;
+ } else if (iRet != RS_RET_OK) {
+ goto finalize_it;
+ }
+ llCookiePrev = llCookie;
}
if(iRetLL != RS_RET_END_OF_LINKEDLIST)