Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit f921622f authored by rswindell's avatar rswindell

Added support for tagged nodes, allowing nodes to be referenced by a single

unique application-defined searchable identifier without requring the node
data (or pointer) comparisons. If anyone uses the listAdd* functions,
they'll need to add the additional tag parameter (this ain't C++).
Added support for primitive non-thread-safe list locking and an "isLocked"
query function.
parent c7aaa82e
......@@ -79,7 +79,7 @@ link_list_t* DLLCALL listInit(link_list_t* list, long flags)
BOOL DLLCALL listFreeNodeData(list_node_t* node)
{
if(node!=NULL && node->data!=NULL && !(node->flags&LINK_LIST_NODE_LOCKED)) {
if(node!=NULL && node->data!=NULL && !(node->flags&LINK_LIST_LOCKED)) {
free(node->data);
node->data = NULL;
return(TRUE);
......@@ -94,7 +94,7 @@ long DLLCALL listFreeNodes(link_list_t* list)
for(node=list->first; node!=NULL; node=next) {
if(node->flags&LINK_LIST_NODE_LOCKED)
if(node->flags&LINK_LIST_LOCKED)
break;
if((list->flags&LINK_LIST_ALWAYS_FREE || node->flags&LINK_LIST_MALLOC)
......@@ -223,14 +223,23 @@ BOOL DLLCALL listSemTryWaitBlock(link_list_t* list, unsigned long timeout)
#endif
void DLLCALL listLock(const link_list_t* list)
BOOL DLLCALL listLock(link_list_t* list)
{
MUTEX_LOCK(list);
list->flags|=LINK_LIST_LOCKED;
return(TRUE);
}
void DLLCALL listUnlock(const link_list_t* list)
BOOL DLLCALL listIsLocked(const link_list_t* list)
{
return((list->flags&LINK_LIST_LOCKED) ? TRUE : FALSE);
}
BOOL DLLCALL listUnlock(link_list_t* list)
{
list->flags&=~LINK_LIST_LOCKED;
MUTEX_UNLOCK(list);
return(TRUE);
}
long DLLCALL listCountNodes(const link_list_t* list)
......@@ -267,6 +276,9 @@ list_node_t* DLLCALL listFindNode(const link_list_t* list, const void* data, siz
if(length==0) {
if(node->data==data)
break;
} else if(data==NULL) {
if(node->tag==(list_node_tag_t)length)
break;
} else if(node->data!=NULL && memcmp(node->data,data,length)==0)
break;
}
......@@ -426,15 +438,15 @@ void* DLLCALL listNodeData(const list_node_t* node)
BOOL DLLCALL listNodeIsLocked(const list_node_t* node)
{
return(node!=NULL && node->flags&LINK_LIST_NODE_LOCKED);
return(node!=NULL && node->flags&LINK_LIST_LOCKED);
}
BOOL DLLCALL listLockNode(list_node_t* node)
{
if(node==NULL || node->flags&LINK_LIST_NODE_LOCKED)
if(node==NULL || node->flags&LINK_LIST_LOCKED)
return(FALSE);
node->flags|=LINK_LIST_NODE_LOCKED;
node->flags|=LINK_LIST_LOCKED;
return(TRUE);
}
......@@ -444,7 +456,7 @@ BOOL DLLCALL listUnlockNode(list_node_t* node)
if(!listNodeIsLocked(node))
return(FALSE);
node->flags&=~LINK_LIST_NODE_LOCKED;
node->flags&=~LINK_LIST_LOCKED;
return(TRUE);
}
......@@ -488,7 +500,7 @@ static list_node_t* DLLCALL list_add_node(link_list_t* list, list_node_t* node,
return(node);
}
list_node_t* DLLCALL listAddNode(link_list_t* list, void* data, list_node_t* after)
list_node_t* DLLCALL listAddNode(link_list_t* list, void* data, list_node_tag_t tag, list_node_t* after)
{
list_node_t* node;
......@@ -500,11 +512,12 @@ list_node_t* DLLCALL listAddNode(link_list_t* list, void* data, list_node_t* aft
memset(node,0,sizeof(list_node_t));
node->data = data;
node->tag = tag;
return(list_add_node(list,node,after));
}
long DLLCALL listAddNodes(link_list_t* list, void** data, list_node_t* after)
long DLLCALL listAddNodes(link_list_t* list, void** data, list_node_tag_t* tag, list_node_t* after)
{
long i;
list_node_t* node=NULL;
......@@ -513,13 +526,13 @@ long DLLCALL listAddNodes(link_list_t* list, void** data, list_node_t* after)
return(-1);
for(i=0; data[i]!=NULL ;i++)
if((node=listAddNode(list,data[i],node==NULL ? after:node))==NULL)
if((node=listAddNode(list,data[i],tag==NULL ? LIST_NODE_TAG_DEFAULT : *(tag++),node==NULL ? after:node))==NULL)
return(i);
return(i);
}
list_node_t* DLLCALL listAddNodeData(link_list_t* list, const void* data, size_t length, list_node_t* after)
list_node_t* DLLCALL listAddNodeData(link_list_t* list, const void* data, size_t length, list_node_tag_t tag, list_node_t* after)
{
list_node_t* node;
void* buf;
......@@ -528,7 +541,7 @@ list_node_t* DLLCALL listAddNodeData(link_list_t* list, const void* data, size_t
return(NULL);
memcpy(buf,data,length);
if((node=listAddNode(list,buf,after))==NULL) {
if((node=listAddNode(list,buf,tag,after))==NULL) {
free(buf);
return(NULL);
}
......@@ -537,7 +550,7 @@ list_node_t* DLLCALL listAddNodeData(link_list_t* list, const void* data, size_t
return(node);
}
list_node_t* DLLCALL listAddNodeString(link_list_t* list, const char* str, list_node_t* after)
list_node_t* DLLCALL listAddNodeString(link_list_t* list, const char* str, list_node_tag_t tag, list_node_t* after)
{
list_node_t* node;
char* buf;
......@@ -548,7 +561,7 @@ list_node_t* DLLCALL listAddNodeString(link_list_t* list, const char* str, list_
if((buf=strdup(str))==NULL)
return(NULL);
if((node=listAddNode(list,buf,after))==NULL) {
if((node=listAddNode(list,buf,tag,after))==NULL) {
free(buf);
return(NULL);
}
......@@ -557,7 +570,7 @@ list_node_t* DLLCALL listAddNodeString(link_list_t* list, const char* str, list_
return(node);
}
long DLLCALL listAddStringList(link_list_t* list, str_list_t str_list, list_node_t* after)
long DLLCALL listAddStringList(link_list_t* list, str_list_t str_list, list_node_tag_t* tag, list_node_t* after)
{
long i;
list_node_t* node=NULL;
......@@ -566,7 +579,7 @@ long DLLCALL listAddStringList(link_list_t* list, str_list_t str_list, list_node
return(-1);
for(i=0; str_list[i]!=NULL ;i++)
if((node=listAddNodeString(list,str_list[i],node==NULL ? after:node))==NULL)
if((node=listAddNodeString(list,str_list[i],tag==NULL ? LIST_NODE_TAG_DEFAULT : *(tag++),node==NULL ? after:node))==NULL)
return(i);
return(i);
......@@ -582,7 +595,7 @@ long DLLCALL listAddNodeList(link_list_t* list, const link_list_t* src, list_nod
return(-1);
for(src_node=src->first; src_node!=NULL; src_node=src_node->next, count++) {
if((node=listAddNode(list, src_node->data, node==NULL ? after:node))==NULL)
if((node=listAddNode(list, src_node->data, src_node->tag, node==NULL ? after:node))==NULL)
return(count);
node->flags = src_node->flags;
}
......@@ -618,7 +631,7 @@ link_list_t* DLLCALL listExtract(link_list_t* dest_list, const list_node_t* node
return(NULL);
for(count=0; count<max && node!=NULL; node=node->next) {
listAddNode(list, node->data, list->last);
listAddNode(list, node->data, node->tag, list->last);
count++;
}
......@@ -636,7 +649,7 @@ static void* list_remove_node(link_list_t* list, list_node_t* node, BOOL free_da
if(node==NULL)
return(NULL);
if(node->flags&LINK_LIST_NODE_LOCKED)
if(node->flags&LINK_LIST_LOCKED)
return(NULL);
if(node->prev!=NULL)
......@@ -677,6 +690,24 @@ void* DLLCALL listRemoveNode(link_list_t* list, list_node_t* node, BOOL free_dat
return(data);
}
void* DLLCALL listRemoveTaggedNode(link_list_t* list, list_node_tag_t tag, BOOL free_data)
{
void* data=NULL;
list_node_t* node;
if(list==NULL)
return(NULL);
MUTEX_LOCK(list);
if((node=listFindTaggedNode(list, tag)) != NULL)
data = list_remove_node(list, node, free_data);
MUTEX_UNLOCK(list);
return(data);
}
long DLLCALL listRemoveNodes(link_list_t* list, list_node_t* node, long max, BOOL free_data)
{
long count;
......@@ -718,8 +749,10 @@ BOOL DLLCALL listSwapNodes(list_node_t* node1, list_node_t* node2)
#endif
tmp=*node1;
node1->tag=node2->tag;
node1->data=node2->data;
node1->flags=node2->flags;
node2->tag=tmp.tag;
node2->data=tmp.data;
node2->flags=tmp.flags;
......
......@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
......@@ -54,29 +54,38 @@ extern "C" {
#define FIRST_NODE ((list_node_t*)NULL) /* Special value to specify first node in list */
#define LAST_NODE ((list_node_t*)-1) /* Special value to specify last node in list */
/* Valid link_list_t.flags bits */
/* Valid link_list_t.flags and list_node_t.flags bits */
#define LINK_LIST_MALLOC (1<<0) /* List/node allocated with malloc() */
#define LINK_LIST_ALWAYS_FREE (1<<1) /* ALWAYS free node data in listFreeNodes() */
#define LINK_LIST_NEVER_FREE (1<<2) /* NEVER free node data (careful of memory leaks!) */
#define LINK_LIST_MUTEX (1<<3) /* Mutex-protected linked-list */
#define LINK_LIST_SEMAPHORE (1<<4) /* Semaphore attached to linked-list */
#define LINK_LIST_NODE_LOCKED (1<<5) /* Node is locked */
#define LINK_LIST_LOCKED (1<<5) /* List or Node is locked */
#define LINK_LIST_ATTACH (1<<6) /* Attach during init */
/* in case the default tag type is not sufficient for your needs, you can over-ride */
#if !defined(list_node_tag_t)
typedef long list_node_tag_t;
#endif
#if !defined(LIST_NODE_TAG_DEFAULT)
#define LIST_NODE_TAG_DEFAULT 0
#endif
typedef struct list_node {
void* data; /* pointer to some kind of data */
struct list_node* next; /* next node in list (or NULL) */
struct list_node* prev; /* previous node in list (or NULL) */
struct link_list* list;
unsigned long flags; /* private use flags */
unsigned long flags; /* private use flags (by this library) */
list_node_tag_t tag; /* application use value */
} list_node_t;
typedef struct link_list {
list_node_t* first; /* first node in list (or NULL) */
list_node_t* last; /* last node in list (or NULL) */
unsigned long flags; /* private use flags */
unsigned long flags; /* private use flags (by this library) */
long count; /* number of nodes in list */
void* private_data; /* for use by the application only */
void* private_data; /* for use by the application/caller */
long refs; /* reference counter (attached clients) */
#if defined(LINK_LIST_THREADSAFE)
pthread_mutex_t mutex;
......@@ -101,9 +110,10 @@ DLLEXPORT BOOL DLLCALL listSemTryWait(link_list_t*);
DLLEXPORT BOOL DLLCALL listSemTryWaitBlock(link_list_t*, unsigned long timeout);
#endif
/* Lock/unlock mutex-protected linked lists (no-op for unprotected lists) */
DLLEXPORT void DLLCALL listLock(const link_list_t*);
DLLEXPORT void DLLCALL listUnlock(const link_list_t*);
/* Lock/unlock linked lists (works best for mutex-protected lists) */
DLLEXPORT BOOL DLLCALL listLock(link_list_t*);
DLLEXPORT BOOL DLLCALL listIsLocked(const link_list_t*);
DLLEXPORT BOOL DLLCALL listUnlock(link_list_t*);
/* Return count or index of nodes, or -1 on error */
DLLEXPORT long DLLCALL listCountNodes(const link_list_t*);
......@@ -128,7 +138,11 @@ DLLEXPORT link_list_t* DLLCALL listExtract(link_list_t* dest_list, const list_no
/* Simple search functions returning found node or NULL on error */
DLLEXPORT list_node_t* DLLCALL listNodeAt(const link_list_t*, long index);
/* Find a specific node by data */
/* Pass length of 0 to search by data pointer rather than by data content comparison (memcmp) */
DLLEXPORT list_node_t* DLLCALL listFindNode(const link_list_t*, const void* data, size_t length);
/* Find a specific node by its tag value */
#define listFindTaggedNode(list, tag) listFindNode(list, NULL, tag)
/* Convenience functions */
DLLEXPORT list_node_t* DLLCALL listFirstNode(const link_list_t*);
......@@ -143,19 +157,21 @@ DLLEXPORT BOOL DLLCALL listUnlockNode(list_node_t*);
DLLEXPORT BOOL DLLCALL listNodeIsLocked(const list_node_t*);
/* Add node to list, returns pointer to new node or NULL on error */
DLLEXPORT list_node_t* DLLCALL listAddNode(link_list_t*, void* data, list_node_t* after /* NULL=insert */);
DLLEXPORT list_node_t* DLLCALL listAddNode(link_list_t*, void* data, list_node_tag_t, list_node_t* after /* NULL=insert */);
/* Add array of node data to list, returns number of nodes added (or negative on error) */
DLLEXPORT long DLLCALL listAddNodes(link_list_t*, void** data, list_node_t* after /* NULL=insert */);
/* tag array may be NULL */
DLLEXPORT long DLLCALL listAddNodes(link_list_t*, void** data, list_node_tag_t*, list_node_t* after /* NULL=insert */);
/* Add node to list, allocating and copying the data for the node */
DLLEXPORT list_node_t* DLLCALL listAddNodeData(link_list_t*, const void* data, size_t length, list_node_t* after);
DLLEXPORT list_node_t* DLLCALL listAddNodeData(link_list_t*, const void* data, size_t length, list_node_tag_t, list_node_t* after);
/* Add node to list, allocating and copying ASCIIZ string data */
DLLEXPORT list_node_t* DLLCALL listAddNodeString(link_list_t*, const char* str, list_node_t* after);
DLLEXPORT list_node_t* DLLCALL listAddNodeString(link_list_t*, const char* str, list_node_tag_t, list_node_t* after);
/* Add a list of strings to the linked list, allocating and copying each */
DLLEXPORT long DLLCALL listAddStringList(link_list_t*, str_list_t, list_node_t* after);
/* tag array may be NULL */
DLLEXPORT long DLLCALL listAddStringList(link_list_t*, str_list_t, list_node_tag_t*, list_node_t* after);
/* Add a list of nodes from a source linked list */
DLLEXPORT long DLLCALL listAddNodeList(link_list_t*, const link_list_t* src, list_node_t* after);
......@@ -168,19 +184,20 @@ DLLEXPORT long DLLCALL listMerge(link_list_t* dest, const link_list_t* src, lis
DLLEXPORT BOOL DLLCALL listSwapNodes(list_node_t* node1, list_node_t* node2);
/* Convenience macros for pushing, popping, and inserting nodes */
#define listPushNode(list, data) listAddNode(list, data, LAST_NODE)
#define listInsertNode(list, data) listAddNode(list, data, FIRST_NODE)
#define listPushNodeData(list, data, length) listAddNodeData(list, data, length, LAST_NODE)
#define listInsertNodeData(list, data, length) listAddNodeData(list, data, length, FIRST_NODE)
#define listPushNodeString(list, str) listAddNodeString(list, str, LAST_NODE)
#define listInsertNodeString(list, str) listAddNodeString(list, str, FIRST_NODE)
#define listPushStringList(list, str_list) listAddStringList(list, str_list, LAST_NODE)
#define listInsertStringList(list, str_list) listAddStringList(list, str_list, FIRST_NODE)
#define listPushNode(list, data) listAddNode(list, data, LIST_NODE_TAG_DEFAULT, LAST_NODE)
#define listInsertNode(list, data) listAddNode(list, data, LIST_NODE_TAG_DEFAULT, FIRST_NODE)
#define listPushNodeData(list, data, length) listAddNodeData(list, data, length, LIST_NODE_TAG_DEFAULT, LAST_NODE)
#define listInsertNodeData(list, data, length) listAddNodeData(list, data, length, LIST_NODE_TAG_DEFAULT, FIRST_NODE)
#define listPushNodeString(list, str) listAddNodeString(list, str, LIST_NODE_TAG_DEFAULT, LAST_NODE)
#define listInsertNodeString(list, str) listAddNodeString(list, str, LIST_NODE_TAG_DEFAULT, FIRST_NODE)
#define listPushStringList(list, str_list) listAddStringList(list, str_list, NULL, LAST_NODE)
#define listInsertStringList(list, str_list) listAddStringList(list, str_list, NULL, FIRST_NODE)
#define listPopNode(list) listRemoveNode(list, LAST_NODE, FALSE)
#define listShiftNode(list) listRemoveNode(list, FIRST_NODE, FALSE)
/* Remove node from list, returning the node's data (if not free'd) */
DLLEXPORT void* DLLCALL listRemoveNode(link_list_t*, list_node_t* /* NULL=first */, BOOL free_data);
DLLEXPORT void* DLLCALL listRemoveTaggedNode(link_list_t*, list_node_tag_t, BOOL free_data);
/* Remove multiple nodes from list, returning the number of nodes removed */
DLLEXPORT long DLLCALL listRemoveNodes(link_list_t*, list_node_t* /* NULL=first */, long count, BOOL free_data);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment