diff --git a/src/xpdev/link_list.c b/src/xpdev/link_list.c
index 06227959bea8daa498a53b7d757fa94686edb186..e6d099180f1666aee503c33db1d4ab4f809e7e7a 100644
--- a/src/xpdev/link_list.c
+++ b/src/xpdev/link_list.c
@@ -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 2004 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2006 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		*
@@ -77,7 +77,7 @@ link_list_t* DLLCALL listInit(link_list_t* list, long flags)
 	return(list);
 }
 
-BOOL listFreeNodeData(list_node_t* node)
+BOOL DLLCALL listFreeNodeData(list_node_t* node)
 {
 	if(node!=NULL && node->data!=NULL && !(node->flags&LINK_LIST_NODE_LOCKED)) {
 		free(node->data);
@@ -87,7 +87,7 @@ BOOL listFreeNodeData(list_node_t* node)
 	return(FALSE);
 }
 
-long listFreeNodes(link_list_t* list)
+long DLLCALL listFreeNodes(link_list_t* list)
 {
 	list_node_t* node;
 	list_node_t* next;
@@ -116,7 +116,7 @@ long listFreeNodes(link_list_t* list)
 	return(list->count);
 }
 
-BOOL listFree(link_list_t* list)
+BOOL DLLCALL listFree(link_list_t* list)
 {
 	if(list==NULL)
 		return(FALSE);
@@ -140,7 +140,7 @@ BOOL listFree(link_list_t* list)
 	return(TRUE);
 }
 
-long listAttach(link_list_t* list)
+long DLLCALL listAttach(link_list_t* list)
 {
 	if(list==NULL)
 		return(-1);
@@ -152,7 +152,7 @@ long listAttach(link_list_t* list)
 	return(list->refs);
 }
 
-long listDettach(link_list_t* list)
+long DLLCALL listDettach(link_list_t* list)
 {
 	int refs;
 
@@ -282,7 +282,7 @@ list_node_t* DLLCALL listFindNode(const link_list_t* list, const void* data, siz
 	return(node);
 }
 
-str_list_t listStringList(const link_list_t* list)
+str_list_t DLLCALL listStringList(const link_list_t* list)
 {
 	list_node_t*	node;
 	str_list_t		str_list;
@@ -306,7 +306,7 @@ str_list_t listStringList(const link_list_t* list)
 	return(str_list);
 }
 
-str_list_t listSubStringList(const list_node_t* node, long max)
+str_list_t DLLCALL listSubStringList(const list_node_t* node, long max)
 {
 	long			count;
 	str_list_t		str_list;
@@ -329,7 +329,7 @@ str_list_t listSubStringList(const list_node_t* node, long max)
 	return(str_list);
 }
 
-void* listFreeStringList(str_list_t list)
+void* DLLCALL listFreeStringList(str_list_t list)
 {
 	strListFree(&list);
 	return(list);
@@ -453,7 +453,7 @@ BOOL DLLCALL listUnlockNode(list_node_t* node)
 	return(TRUE);
 }
 
-static list_node_t* list_add_node(link_list_t* list, list_node_t* node, list_node_t* after)
+static list_node_t* DLLCALL list_add_node(link_list_t* list, list_node_t* node, list_node_t* after)
 {
 	if(list==NULL)
 		return(NULL);
@@ -463,6 +463,9 @@ static list_node_t* list_add_node(link_list_t* list, list_node_t* node, list_nod
 	node->list = list;
 	node->prev = after;
 
+	if(after==LAST_NODE)					/* e.g. listPushNode() */
+		after=list->last;
+
 	if(after==list->last)					/* append to list */
 		list->last = node;
 	if(after==FIRST_NODE) {					/* insert at beginning of list */
@@ -521,7 +524,7 @@ long DLLCALL listAddNodes(link_list_t* list, void** data, list_node_t* after)
 	return(i);
 }
 
-list_node_t* 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_t* after)
 {
 	list_node_t*	node;
 	void*			buf;
@@ -539,7 +542,7 @@ list_node_t* listAddNodeData(link_list_t* list, const void* data, size_t length,
 	return(node);
 }
 
-list_node_t* 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_t* after)
 {
 	list_node_t*	node;
 	char*			buf;
@@ -634,8 +637,11 @@ void* DLLCALL listRemoveNode(link_list_t* list, list_node_t* node, BOOL free_dat
 	if(list==NULL)
 		return(NULL);
 
+	/* Should these lines be mutex protected? */
 	if(node==FIRST_NODE)
 		node=list->first;
+	if(node==LAST_NODE)
+		node=list->last;
 	if(node==NULL)
 		return(NULL);
 
@@ -668,7 +674,7 @@ void* DLLCALL listRemoveNode(link_list_t* list, list_node_t* node, BOOL free_dat
 	return(data);
 }
 
-long listRemoveNodes(link_list_t* list, list_node_t* node, long max, BOOL free_data)
+long DLLCALL listRemoveNodes(link_list_t* list, list_node_t* node, long max, BOOL free_data)
 {
 	long count;
 
diff --git a/src/xpdev/link_list.h b/src/xpdev/link_list.h
index eb33cdfb397dd7364dc4bf2efa23a32cc69194af..74403afed0b64f06091741fa1e2b5f532bf71cce 100644
--- a/src/xpdev/link_list.h
+++ b/src/xpdev/link_list.h
@@ -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 2005 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2006 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		*
@@ -51,7 +51,8 @@
 extern "C" {
 #endif
 
-#define FIRST_NODE				NULL	/* Special value to specify first node in list */
+#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 */
 #define LINK_LIST_MALLOC		(1<<0)	/* List/node allocated with malloc() */
@@ -85,41 +86,41 @@ typedef struct link_list {
 
 /* Initialization, Allocation, and Freeing of Lists and Nodes */
 DLLEXPORT link_list_t*	DLLCALL listInit(link_list_t* /* NULL to auto-allocate */, long flags);
-BOOL			listFree(link_list_t*);
-long			listFreeNodes(link_list_t*);
-BOOL			listFreeNodeData(list_node_t* node);
+DLLEXPORT BOOL			DLLCALL listFree(link_list_t*);
+DLLEXPORT long			DLLCALL listFreeNodes(link_list_t*);
+DLLEXPORT BOOL			DLLCALL listFreeNodeData(list_node_t* node);
 
 /* Increment/decrement reference counter (and auto-free when zero), returns -1 on error */
-long			listAttach(link_list_t*);
-long			listDetach(link_list_t*);
+DLLEXPORT long	DLLCALL listAttach(link_list_t*);
+DLLEXPORT long	DLLCALL listDetach(link_list_t*);
 
 #if defined(LINK_LIST_THREADSAFE)
-DLLEXPORT BOOL		DLLCALL	listSemPost(link_list_t*);
-DLLEXPORT BOOL		DLLCALL	listSemWait(link_list_t*);
-DLLEXPORT BOOL		DLLCALL	listSemTryWait(link_list_t*);
-DLLEXPORT BOOL		DLLCALL	listSemTryWaitBlock(link_list_t*, unsigned long timeout);
+DLLEXPORT BOOL	DLLCALL	listSemPost(link_list_t*);
+DLLEXPORT BOOL	DLLCALL	listSemWait(link_list_t*);
+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*);
+DLLEXPORT void	DLLCALL	listLock(const link_list_t*);
+DLLEXPORT void	DLLCALL	listUnlock(const link_list_t*);
 
 /* Return count or index of nodes, or -1 on error */
-DLLEXPORT long		DLLCALL	listCountNodes(const link_list_t*);
-DLLEXPORT long		DLLCALL	listNodeIndex(const link_list_t*, list_node_t*);
+DLLEXPORT long	DLLCALL	listCountNodes(const link_list_t*);
+DLLEXPORT long	DLLCALL	listNodeIndex(const link_list_t*, list_node_t*);
 
 /* Get/Set list private data */
-DLLEXPORT void*		DLLCALL	listSetPrivateData(link_list_t*, void*);
-DLLEXPORT void*		DLLCALL	listGetPrivateData(link_list_t*);
+DLLEXPORT void*	DLLCALL	listSetPrivateData(link_list_t*, void*);
+DLLEXPORT void*	DLLCALL	listGetPrivateData(link_list_t*);
 
 /* Return an allocated string list (which must be freed), array of all strings in linked list */
-str_list_t		listStringList(const link_list_t*);
+DLLEXPORT str_list_t DLLCALL listStringList(const link_list_t*);
 
 /* Return an allocated string list (which must be freed), subset of strings in linked list */
-str_list_t		listSubStringList(const list_node_t*, long max);
+DLLEXPORT str_list_t DLLCALL listSubStringList(const list_node_t*, long max);
 
 /* Free a string list returned from either of the above functions */
-void*			listFreeStringList(str_list_t);
+DLLEXPORT void*	DLLCALL listFreeStringList(str_list_t);
 
 /* Extract subset (up to max number of nodes) in linked list (src_node) and place into dest_list */
 /* dest_list == NULL, then allocate a return a new linked list */
@@ -137,9 +138,9 @@ DLLEXPORT list_node_t*	DLLCALL	listPrevNode(const list_node_t*);
 DLLEXPORT void*			DLLCALL	listNodeData(const list_node_t*);
 
 /* Primitive node locking */
-DLLEXPORT BOOL		DLLCALL	listLockNode(list_node_t*);
-DLLEXPORT BOOL		DLLCALL	listUnlockNode(list_node_t*);
-DLLEXPORT BOOL		DLLCALL	listNodeIsLocked(const list_node_t*);
+DLLEXPORT BOOL DLLCALL	listLockNode(list_node_t*);
+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 */);
@@ -148,10 +149,10 @@ DLLEXPORT list_node_t*	DLLCALL	listAddNode(link_list_t*, void* data, list_node_t
 DLLEXPORT long		DLLCALL	listAddNodes(link_list_t*, void** data, list_node_t* after /* NULL=insert */);
 
 /* Add node to list, allocating and copying the data for the node */
-list_node_t*	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_t* after);
 
 /* Add node to list, allocating and copying ASCIIZ string data */
-list_node_t*	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_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);
@@ -167,22 +168,22 @@ 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, listLastNode(list))
+#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, listLastNode(list))
+#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, listLastNode(list))
+#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, listLastNode(list))
+#define	listPushStringList(list, str_list)		listAddStringList(list, str_list, LAST_NODE)
 #define listInsertStringList(list, str_list)	listAddStringList(list, str_list, FIRST_NODE)
-#define listPopNode(list)						listRemoveNode(list, listLastNode(list), FALSE)
+#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	listRemoveNode(link_list_t*, list_node_t* /* NULL=first */, BOOL free_data);
 
 /* Remove multiple nodes from list, returning the number of nodes removed */
-long			listRemoveNodes(link_list_t*, list_node_t* /* NULL=first */, long count, BOOL free_data);
+DLLEXPORT long	DLLCALL	listRemoveNodes(link_list_t*, list_node_t* /* NULL=first */, long count, BOOL free_data);
 
 #if defined(__cplusplus)
 }