The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
cslist.c
Go to the documentation of this file.
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: clist.c
8  * Author : Kyle Loudon/Dan Levin
9  * Date : Mon Apr 08 12:24:12 2013
10  * Version : 0.51
11  * ---
12  * Description: A circular, singly-linked list - implemented as a pure, generic ADT
13  *
14  * Date Revision message
15  * 130413 Created this file
16  * 150331 This code ready for version 0.51
17  *
18  */
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include "cslist.h"
27 
29 {
30  void *data;
31  struct CSListElmt_ *next;
32 };
33 
34 struct CSList_
35 {
36  int size;
37  int (*match)(const void *key1, const void *key2);
38  void (*destroy)(void *data);
39  struct CSListElmt_ *head;
40 };
41 
42 /* FUNCTION DEFINITIONS --------------------------------------------------- */
43 
44 CSlist CSLISTinit(void (*destroy)(void *data))
45 {
46  CSlist clist;
47 
48  if ((clist = (CSlist)malloc(sizeof(struct CSList_)))==NULL)
49  return NULL;
50 
51  clist->size = 0;
52  clist->match = NULL;
53  clist->destroy = destroy;
54  clist->head = NULL;
55 
56  return clist;
57 }
58 
59 void CSLISTdestroy(CSlist clist)
60 {
61  void *data;
62 
63  while (CSLISTsize(clist) > 0)
64  {
65  if (CSLISTremnext(clist, clist->head, (void **)&data) == 0 && clist->destroy !=
66  NULL)
67  clist->destroy(data);
68  }
69  free(clist);
70 }
71 
72 int CSLISTinsnext(CSlist clist, CSlistNode node, const void *data)
73 {
74  CSlistNode newnode;
75 
76  /* Allocate storage for new node */
77  if ((newnode = (CSlistNode)malloc(sizeof(struct CSListElmt_))) == NULL)
78  return -1;
79 
80  newnode->data = (void *)data;
81 
82  if (CSLISTsize(clist) == 0)
83  {
84  /* Handle insertion when the list is empty */
85  newnode->next = newnode;
86  clist->head = newnode;
87  }
88  else
89  {
90  /* Handle insertion when the list is not empty */
91  newnode->next = node->next;
92  node->next = newnode;
93  }
94 
95  /* Adjust list size to account for the new node */
96  clist->size++;
97 
98  return 0;
99 }
100 
101 int CSLISTremnext(CSlist clist, CSlistNode node, void **data)
102 {
103 
104  CSlistNode oldnode;
105 
106  /* Don't allow removal from an empty list */
107  if (clist->size == 0)
108  return -1;
109 
110  /* Remove the node from the list */
111  *data = node->next->data;
112 
113  if (node->next == node)
114  {
115  /* Handle removing the last element */
116  oldnode = node->next;
117  clist->head = NULL;
118  }
119  else
120  {
121  /* Handle removing other than the last element */
122  oldnode = node->next;
123  node->next = node->next->next;
124 
125  if (oldnode == clist->head)
126  clist->head = oldnode->next;
127  }
128 
129  /* Free storage occupied by the old element */
130  free(oldnode);
131 
132  /* Adjust list size to account for the removal */
133  clist->size--;
134 
135  return 0;
136 }
137 
138 int CSLISTsize(CSlist clist)
139 {
140  return clist->size;
141 }
142 
144 {
145  return clist->head;
146 }
147 
149 {
150  return clist->head==node ? 1 : 0;
151 }
152 
154 {
155  return node->data;
156 }
157 
159 {
160  return node->next;
161 }
162 
163 CSlistNode CSLISTfindnode(CSlist clist, const void *data)
164 {
165  CSlistNode member = NULL;
166  int head_hit;
167 
168  /* Match callback not set - or empty list - not allowed.. */
169  if (clist->match == NULL || clist->size == 0)
170  return NULL;
171 
172  member = clist->head;
173  head_hit = 0;
174 
175  do
176  {
177  if (clist->match(data, CSLISTdata(member)))
178  {
179  if (member == clist->head)
180  head_hit = 1;
181  break;
182  }
183  member = member->next;
184  } while (member != clist->head);
185 
186  if (member == clist->head && !head_hit) /* Node not found */
187  return NULL;
188  else
189  return member; /* We have a hit - somewhere in the list... */
190 }
191 
192 void CSLISTsetmatch(CSlist clist, int (*match)(const void *key1, const void *key2))
193 {
194  clist->match = match;
195 }
196 
197 int CSLISTfind_remove(CSlist clist, void **data)
198 {
199  CSlistNode member, prev;
200  int head_hit;
201 
202  /* If match-callback not set */
203  if (clist->match == NULL)
204  return -2;
205 
206  /* If list empty.. - node can not be found! */
207  if (!clist->size)
208  return 1;
209 
210  /* Initialize 'prev' with node prior to head node... */
211  prev = clist->head;
212  while (prev->next != clist->head)
213  prev = prev->next;
214 
215  member = clist->head;
216  head_hit = 0;
217 
218  do
219  {
220  if (clist->match(*data, CSLISTdata(member)))
221  {
222  if (member == clist->head)
223  head_hit = 1;
224  break;
225  }
226  prev = member;
227  member = member->next;
228  } while (member != clist->head);
229 
230  /* Node not found */
231  if (member == clist->head && !head_hit)
232  return 1;
233 
234  /* Perform the removal.. */
235  if (clist->size == 1)
236  {
237  *data = clist->head->data;
238  free(clist->head);
239  clist->head = NULL;
240  clist->size--;
241  return 0;
242  }
243  else
244  return CSLISTremnext(clist, prev, data);
245 }
246 
247 void CSLISTtraverse(CSlist clist, void (*callback)(const void *data))
248 {
249  CSlistNode curr;
250 
251  if (clist->size)
252  {
253  curr = clist->head;
254 
255  do
256  {
257  callback(curr->data);
258  curr = curr->next;
259  } while (curr != clist->head);
260  }
261 }