1 /*
2   Copyright (C) 2005, 2008, 2011, 2016 Rocky Bernstein <rocky@gnu.org>
3   Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
4 
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 # define __CDIO_CONFIG_H__ 1
22 #endif
23 
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 
31 #include <cdio/ds.h>
32 #include <cdio/util.h>
33 #include <cdio/types.h>
34 #include "cdio_assert.h"
35 
36 struct _CdioList
37 {
38   unsigned length;
39 
40   CdioListNode_t *begin;
41   CdioListNode_t *end;
42 };
43 
44 struct _CdioListNode
45 {
46   CdioList_t *list;
47 
48   CdioListNode_t *next;
49 
50   void *data;
51 };
52 
53 /* impl */
54 
55 CdioList_t *
_cdio_list_new(void)56 _cdio_list_new (void)
57 {
58   CdioList_t *p_new_obj = calloc (1, sizeof (CdioList_t));
59 
60   return p_new_obj;
61 }
62 
63 void
_cdio_list_free(CdioList_t * p_list,int free_data,CdioDataFree_t free_fn)64 _cdio_list_free (CdioList_t *p_list, int free_data, CdioDataFree_t free_fn)
65 {
66   while (_cdio_list_length (p_list))
67     _cdio_list_node_free (_cdio_list_begin (p_list), free_data, free_fn);
68 
69   free (p_list);
70 }
71 
72 unsigned
_cdio_list_length(const CdioList_t * p_list)73 _cdio_list_length (const CdioList_t *p_list)
74 {
75   cdio_assert (p_list != NULL);
76 
77   return p_list->length;
78 }
79 
80 void
_cdio_list_prepend(CdioList_t * p_list,void * p_data)81 _cdio_list_prepend (CdioList_t *p_list, void *p_data)
82 {
83   CdioListNode_t *p_new_node;
84 
85   cdio_assert (p_list != NULL);
86 
87   p_new_node = calloc (1, sizeof (CdioListNode_t));
88   cdio_assert (p_new_node != NULL);
89 
90   p_new_node->list = p_list;
91   p_new_node->next = p_list->begin;
92   p_new_node->data = p_data;
93 
94   p_list->begin = p_new_node;
95   if (p_list->length == 0)
96     p_list->end = p_new_node;
97 
98   p_list->length++;
99 }
100 
101 void
_cdio_list_append(CdioList_t * p_list,void * p_data)102 _cdio_list_append (CdioList_t *p_list, void *p_data)
103 {
104   cdio_assert (p_list != NULL);
105 
106   if (p_list->length == 0)
107     {
108       _cdio_list_prepend (p_list, p_data);
109     }
110   else
111     {
112       CdioListNode_t *p_new_node = calloc (1, sizeof (CdioListNode_t));
113       cdio_assert (p_new_node != NULL);
114 
115       p_new_node->list = p_list;
116       p_new_node->next = NULL;
117       p_new_node->data = p_data;
118 
119       p_list->end->next = p_new_node;
120       p_list->end = p_new_node;
121 
122       p_list->length++;
123     }
124 }
125 
126 void
_cdio_list_foreach(CdioList_t * p_list,_cdio_list_iterfunc_t func,void * p_user_data)127 _cdio_list_foreach (CdioList_t *p_list, _cdio_list_iterfunc_t func,
128                     void *p_user_data)
129 {
130   CdioListNode_t *node;
131 
132   cdio_assert (p_list != NULL);
133   cdio_assert (func != 0);
134 
135   for (node = _cdio_list_begin (p_list);
136        node != NULL;
137        node = _cdio_list_node_next (node))
138     func (_cdio_list_node_data (node), p_user_data);
139 }
140 
141 CdioListNode_t *
_cdio_list_find(CdioList_t * p_list,_cdio_list_iterfunc_t cmp_func,void * p_user_data)142 _cdio_list_find (CdioList_t *p_list, _cdio_list_iterfunc_t cmp_func,
143                  void *p_user_data)
144 {
145   CdioListNode_t *p_node;
146 
147   cdio_assert (p_list != NULL);
148   cdio_assert (cmp_func != 0);
149 
150   for (p_node = _cdio_list_begin (p_list);
151        p_node != NULL;
152        p_node = _cdio_list_node_next (p_node))
153     if (cmp_func (_cdio_list_node_data (p_node), p_user_data))
154       break;
155 
156   return p_node;
157 }
158 
159 CdioListNode_t *
_cdio_list_begin(const CdioList_t * p_list)160 _cdio_list_begin (const CdioList_t *p_list)
161 {
162   cdio_assert (p_list != NULL);
163 
164   return p_list->begin;
165 }
166 
167 CdioListNode_t *
_cdio_list_end(CdioList_t * p_list)168 _cdio_list_end (CdioList_t *p_list)
169 {
170   cdio_assert (p_list != NULL);
171 
172   return p_list->end;
173 }
174 
175 CdioListNode_t *
_cdio_list_node_next(CdioListNode_t * p_node)176 _cdio_list_node_next (CdioListNode_t *p_node)
177 {
178   if (p_node)
179     return p_node->next;
180 
181   return NULL;
182 }
183 
184 void
_cdio_list_node_free(CdioListNode_t * p_node,int free_data,CdioDataFree_t free_fn)185 _cdio_list_node_free (CdioListNode_t *p_node,
186                       int free_data, CdioDataFree_t free_fn)
187 {
188   CdioList_t *p_list;
189   CdioListNode_t *prev_node;
190 
191   cdio_assert (p_node != NULL);
192 
193   p_list = p_node->list;
194 
195   cdio_assert (_cdio_list_length (p_list) > 0);
196 
197   if (free_data && free_fn)
198     free_fn (_cdio_list_node_data (p_node));
199 
200   if (_cdio_list_length (p_list) == 1)
201     {
202       cdio_assert (p_list->begin == p_list->end);
203 
204       p_list->end = p_list->begin = NULL;
205       p_list->length = 0;
206       free (p_node);
207       return;
208     }
209 
210   cdio_assert (p_list->begin != p_list->end);
211 
212   if (p_list->begin == p_node)
213     {
214       p_list->begin = p_node->next;
215       free (p_node);
216       p_list->length--;
217       return;
218     }
219 
220   for (prev_node = p_list->begin; prev_node->next; prev_node = prev_node->next)
221     if (prev_node->next == p_node)
222       break;
223 
224   cdio_assert (prev_node->next != NULL);
225 
226   if (p_list->end == p_node)
227     p_list->end = prev_node;
228 
229   prev_node->next = p_node->next;
230 
231   p_list->length--;
232 
233   free (p_node);
234 }
235 
236 void *
_cdio_list_node_data(CdioListNode_t * p_node)237 _cdio_list_node_data (CdioListNode_t *p_node)
238 {
239   if (p_node)
240     return p_node->data;
241 
242   return NULL;
243 }
244 
245 /* eof */
246 
247 
248 /*
249  * Local variables:
250  *  c-file-style: "gnu"
251  *  tab-width: 8
252  *  indent-tabs-mode: nil
253  * End:
254  */
255