Added SILC Server library.
[silc.git] / lib / silcutil / silcdlist.h
index f6fcd71420065fd27cda8232880ff5b9654d46d6..d205ede0a9a1a55e91e05024edd097ff441a0efa 100644 (file)
@@ -2,15 +2,14 @@
 
   silcdlist.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 #define SILDCLIST_H
 
 #include "silclist.h"
+
 /****h* silcutil/SILC Dynamic List Interface
  *
  * DESCRIPTION
  *
- *    SILC Dynamic List API can be used to add opaque contexts to list that
- *    will automatically allocate list entries.  Normal SILC List API cannot
- *    be used for this purpose because in that case the context passed to the
- *    list must be defined as list structure already.  This is not the case in
- *    SilcDList.
+ * SILC Dynamic List API can be used to add opaque contexts to list that
+ * will automatically allocate list entries.  Normal SILC List API cannot
+ * be used for this purpose because in that case the context passed to the
+ * list must be defined as list structure already.  This is not the case in
+ * SilcDList.
  *
- *    This is slower than SilcList because this requires one extra memory
- *    allocation when adding new entries to the list.  The context is probably
- *    allocated already and the new list entry requires one additional memory
- *    allocation.  The memory allocation and freeing is done automatically in
- *    the API and does not show to the caller.
+ * This is slower than SilcList because this requires one extra memory
+ * allocation when adding new entries to the list.  The context is probably
+ * allocated already and the new list entry requires one additional memory
+ * allocation.  The memory allocation and freeing is done automatically in
+ * the API and does not show to the caller.
  *
  ***/
 
  *
  * SOURCE
  */
-typedef struct {
+typedef struct SilcDListStruct {
   SilcList list;
+  void *current;
+  void *prev;
 } *SilcDList;
 /***/
 
@@ -65,14 +66,15 @@ typedef struct {
 typedef struct SilcDListEntryStruct {
   void *context;
   struct SilcDListEntryStruct *next;
+  struct SilcDListEntryStruct *prev;
 } *SilcDListEntry;
 
 /****f* silcutil/SilcDListAPI/silc_dlist_init
  *
  * SYNOPSIS
- * 
+ *
  *    static inline
- *    SilcDList silc_dlist_init();
+ *    SilcDList silc_dlist_init(void);
  *
  * DESCRIPTION
  *
@@ -81,12 +83,15 @@ typedef struct SilcDListEntryStruct {
  ***/
 
 static inline
-SilcDList silc_dlist_init()
+SilcDList silc_dlist_init(void)
 {
   SilcDList list;
 
-  list = (SilcDList)silc_calloc(1, sizeof(*list));
-  silc_list_init(list->list, struct SilcDListEntryStruct, next);
+  list = (SilcDList)silc_malloc(sizeof(*list));
+  if (!list)
+    return NULL;
+  list->current = list->prev = NULL;
+  silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
 
   return list;
 }
@@ -148,7 +153,7 @@ int silc_dlist_count(SilcDList list)
  * DESCRIPTION
  *
  *    Set the start of the list. This prepares the list for traversing entries
- *    from the start of the list.
+ *    from the start of the list towards end of the list.
  *
  ***/
 
@@ -156,6 +161,28 @@ static inline
 void silc_dlist_start(SilcDList list)
 {
   silc_list_start(list->list);
+  list->current = list->prev = NULL;
+}
+
+/****f* silcutil/SilcDListAPI/silc_dlist_end
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_dlist_end(SilcDList list);
+ *
+ * DESCRIPTION
+ *
+ *    Set the end of the list. This prepares the list for traversing entries
+ *    from the end of the list towards start of the list.
+ *
+ ***/
+
+static inline
+void silc_dlist_end(SilcDList list)
+{
+  silc_list_end(list->list);
+  list->current = list->prev = NULL;
 }
 
 /****f* silcutil/SilcDListAPI/silc_dlist_add
@@ -163,7 +190,7 @@ void silc_dlist_start(SilcDList list)
  * SYNOPSIS
  *
  *    static inline
- *    void silc_dlist_add(SilcDList list, void *context);
+ *    SilcBool silc_dlist_add(SilcDList list, void *context);
  *
  * DESCRIPTION
  *
@@ -173,11 +200,40 @@ void silc_dlist_start(SilcDList list)
  ***/
 
 static inline
-void silc_dlist_add(SilcDList list, void *context)
+SilcBool silc_dlist_add(SilcDList list, void *context)
 {
-  SilcDListEntry e = (SilcDListEntry)silc_calloc(1, sizeof(*e));
+  SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
+  if (!e)
+    return FALSE;
   e->context = context;
   silc_list_add(list->list, e);
+  return TRUE;
+}
+
+/****f* silcutil/SilcDList/silc_dlist_insert
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_dlist_insert(SilcDList list, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Insert new entry to the list between current and previous entry.
+ *    If list is at the start this adds the entry at head of the list.
+ *    Use silc_dlist_add to add at the end of the list.
+ *
+ ***/
+
+static inline
+SilcBool silc_dlist_insert(SilcDList list, void *context)
+{
+  SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
+  if (!e)
+    return FALSE;
+  e->context = context;
+  silc_list_insert(list->list, list->prev, e);
+  return TRUE;
 }
 
 /****f* silcutil/SilcDListAPI/silc_dlist_del
@@ -202,6 +258,13 @@ void silc_dlist_del(SilcDList list, void *context)
   while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
     if (e->context == context) {
       silc_list_del(list->list, e);
+#if defined(SILC_DEBUG)
+      memset(e, 'F', sizeof(*e));
+#endif
+      if (list->current == e)
+       list->current = NULL;
+      if (list->prev == e)
+       list->prev = NULL;
       silc_free(e);
       break;
     }
@@ -220,12 +283,12 @@ void silc_dlist_del(SilcDList list, void *context)
  *    Returns current entry from the list and moves the list pointer forward
  *    so that calling this next time returns the next entry from the list.
  *    This can be used to traverse the list. Return SILC_LIST_END when the
- *    entire list has been traversed. Later, silc_list_start must be called
- *    again when re-starting list traversing.
+ *    entire list has been traversed. Later, silc_list_start (or
+ *    silc_dlist_end) must be called again when re-starting list traversing.
  *
  * EXAMPLE
  *
- *    // Traverse the list from the beginning to the end 
+ *    // Traverse the list from the beginning to the end
  *    silc_dlist_start(list)
  *    while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
  *      ...
@@ -236,7 +299,9 @@ void silc_dlist_del(SilcDList list, void *context)
 static inline
 void *silc_dlist_get(SilcDList list)
 {
-  SilcDListEntry e = (SilcDListEntry)silc_list_get(list->list);
+  SilcDListEntry e;
+  list->prev = list->current;
+  list->current = e = (SilcDListEntry)silc_list_get(list->list);
   if (e != SILC_LIST_END)
     return e->context;
   return SILC_LIST_END;