diff --git a/src/xpdev/link_list.c b/src/xpdev/link_list.c new file mode 100644 index 0000000000000000000000000000000000000000..1f2d60cb0a36b3f2e8cc6fd30785717efc745250 --- /dev/null +++ b/src/xpdev/link_list.c @@ -0,0 +1,309 @@ +/* link_list.c */ + +/* Double-Linked-list library */ + +/* $Id$ */ + +/**************************************************************************** + * @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 * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include <stdlib.h> /* malloc */ +#include <string.h> /* memset */ +#include "link_list.h" + +link_list_t* listInit(link_list_t* list, unsigned long flags) +{ + if(flags&LINK_LIST_MALLOC || list==NULL) { + if((list=(link_list_t*)malloc(sizeof(link_list_t)))==NULL) + return(NULL); + flags |= LINK_LIST_MALLOC; + } + + memset(list,0,sizeof(link_list_t)); + + list->flags = flags; + + return(list); +} + +void listFreeNodeData(list_node_t* node) +{ + if(node!=NULL && node->data!=NULL) { + free(node->data); + node->data = NULL; + } +} + +void listFreeNodes(link_list_t* list) +{ + list_node_t* node; + list_node_t* next; + + for(node=list->first; node!=NULL; node=next) { + + if(list->flags&LINK_LIST_AUTO_FREE) + listFreeNodeData(node); + + next = node->next; + + free(node); + } + + list->first = NULL; + list->last = NULL; + list->count = 0; +} + +link_list_t* listFree(link_list_t* list) +{ + if(list==NULL) + return(NULL); + + listFreeNodes(list); + + if(list->flags&LINK_LIST_MALLOC) + free(list), list=NULL; + + return(list); +} + +size_t listCountNodes(const link_list_t* list) +{ + size_t count=0; + list_node_t* node; + + if(list==NULL) + return(0); + + if(list->count) + return(list->count); + + for(node=list->first; node!=NULL; node=node->next) + count++; + + return(count); +} + +list_node_t* listFirstNode(const link_list_t* list) +{ + if(list==NULL) + return(NULL); + + return(list->first); +} + +list_node_t* listLastNode(const link_list_t* list) +{ + list_node_t* node; + list_node_t* last=NULL; + + if(list==NULL) + return(NULL); + + if(list->last!=NULL) + return(list->last); + + for(node=list->first; node!=NULL; node=node->next) + last=node; + + return(last); +} + +list_node_t* listNextNode(const list_node_t* node) +{ + if(node==NULL) + return(NULL); + + return(node->next); +} + +list_node_t* listPrevNode(const list_node_t* node) +{ + if(node==NULL) + return(NULL); + + return(node->prev); +} + +void* listNodeData(const list_node_t* node) +{ + if(node==NULL) + return(NULL); + + return(node->data); +} + +list_node_t* listAddNode(link_list_t* list, void* data, list_node_t* after) +{ + list_node_t* node; + + if(list==NULL) + return(NULL); + + if((node=(list_node_t*)malloc(sizeof(list_node_t)))==NULL) + return(NULL); + + memset(node,0,sizeof(list_node_t)); + + node->data = data; + node->prev = after; + + if(after==list->last) /* append to list */ + list->last = node; + if(after==NULL && list->first!=NULL) { /* insert at beginning of list */ + list->first->prev = node; + list->first = node; + } + if(after!=NULL) { + if(after->next!=NULL) { + after->next->prev = node; + node->next = after->next; + } + after->next = node; + } + + list->count++; + + return(node); +} + + +list_node_t* listPushNode(link_list_t* list, void* data) +{ + return(listAddNode(list, data, listLastNode(list))); +} + +list_node_t* listInsertNode(link_list_t* list, void* data) +{ + return(listAddNode(list, data, NULL)); +} + +list_node_t* listAddNodeData(link_list_t* list, const void* data, size_t length, list_node_t* after) +{ + list_node_t* node; + void* buf; + + if((buf=malloc(length))==NULL) + return(NULL); + memcpy(buf,data,length); + + if((node=listAddNode(list,buf,after))==NULL) { + free(buf); + return(NULL); + } + + return(node); +} + +list_node_t* listPushNodeData(link_list_t* list, const void* data, size_t length) +{ + return(listAddNodeData(list, data, length, listLastNode(list))); +} + +list_node_t* listInsertNodeData(link_list_t* list, const void* data, size_t length) +{ + return(listAddNodeData(list, data, length, NULL)); +} + +list_node_t* listAddNodeString(link_list_t* list, const char* str, list_node_t* after) +{ + list_node_t* node; + char* buf; + size_t length; + + if(str==NULL) + return(NULL); + + length = strlen(str)+1; + + if((buf=malloc(length))==NULL) + return(NULL); + memcpy(buf,str,length); + + if((node=listAddNode(list,buf,after))==NULL) { + free(buf); + return(NULL); + } + + return(node); +} + +list_node_t* listPushNodeString(link_list_t* list, const char* str) +{ + return(listAddNodeString(list, str, listLastNode(list))); +} + +list_node_t* listInsertNodeString(link_list_t* list, const char* str) +{ + return(listAddNodeString(list, str, NULL)); +} + +void* listRemoveNode(link_list_t* list, list_node_t* node) +{ + void* data; + + if(list==NULL || node==NULL) + return(NULL); + + if(node->prev!=NULL) + node->prev->next = node->next; + if(node->next!=NULL) + node->next->prev = node->prev; + if(list->first==node) + list->first = node->next; + if(list->last==node) + list->last = node->prev; + + if(list->flags&LINK_LIST_AUTO_FREE) + listFreeNodeData(node); + data=node->data; + + free(node); + + if(list->count) + list->count--; + + return(data); +} + +void listRemoveNodeData(link_list_t* list, list_node_t* node) +{ + void* data; + + if((data=listRemoveNode(list, node))!=NULL) + free(data); +} + + +void* listPopNode(link_list_t* list) +{ + return(listRemoveNode(list, listLastNode(list))); +} diff --git a/src/xpdev/link_list.h b/src/xpdev/link_list.h new file mode 100644 index 0000000000000000000000000000000000000000..3f720335068a95bbf66e0ffe67e40a8a4e7f798d --- /dev/null +++ b/src/xpdev/link_list.h @@ -0,0 +1,102 @@ +/* link_list.h */ + +/* Double-Linked-list library */ + +/* $Id$ */ + +/**************************************************************************** + * @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 * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#ifndef _LINK_LIST_H +#define _LINK_LIST_H + +#include <stddef.h> /* size_t */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Valid link_list_t.flags bits */ +#define LINK_LIST_MALLOC (1<<0) /* List allocated with malloc() */ +#define LINK_LIST_AUTO_FREE (1<<1) /* Free node data automatically */ + +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) */ +} list_node_t; + +typedef struct { + list_node_t* first; /* first node in list (or NULL) */ + list_node_t* last; /* last node in list (or NULL) */ + unsigned long flags; /* flags passed to listInit() */ + size_t count; /* number of nodes in list */ +} link_list_t; + +/* Initialization, Allocation, and Freeing of Lists and Nodes */ +link_list_t* listInit(link_list_t*, unsigned long flags); +link_list_t* listFree(link_list_t*); +void listFreeNodes(link_list_t*); +void listFreeNodeData(list_node_t* node); + +/* Convenience functions */ +size_t listCountNodes(const link_list_t*); +list_node_t* listFirstNode(const link_list_t*); +list_node_t* listLastNode(const link_list_t*); +list_node_t* listNextNode(const list_node_t*); +list_node_t* listPrevNode(const list_node_t*); +void* listNodeData(const list_node_t*); + +/* Add node to list, returns pointer to new node */ +list_node_t* listAddNode(link_list_t*, void* data, list_node_t* after); +list_node_t* listPushNode(link_list_t*, void* data); +list_node_t* listInsertNode(link_list_t*, void* data); + +/* 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); +list_node_t* listPushNodeData(link_list_t*, const void* data, size_t length); +list_node_t* listInsertNodeData(link_list_t*, const void* data, size_t length); + +/* Add node to list, allocating and copying string (ACIIZ / null-terminated char*) */ +list_node_t* listAddNodeString(link_list_t*, const char* str, list_node_t* after); +list_node_t* listPushNodeString(link_list_t*, const char* str); +list_node_t* listInsertNodeString(link_list_t*, const char* str); + +/* Remove node from list, returning the node's data (if not free'd) */ +void* listPopNode(link_list_t*); +void* listRemoveNode(link_list_t*, list_node_t*); +void listRemoveNodeData(link_list_t* list, list_node_t* node); + +#if defined(__cplusplus) +} +#endif + +#endif /* Don't add anything after this line */