1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 1999-2021 Free Software Foundation, Inc.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 3 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General
15    Public License along with this library.  If not, see
16    <http://www.gnu.org/licenses/>. */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <errno.h>
23 #include <stdlib.h>
24 
25 #include <mailutils/sys/list.h>
26 #include <mailutils/sys/iterator.h>
27 #include <mailutils/errno.h>
28 
29 int
mu_iterator_create(mu_iterator_t * piterator,void * owner)30 mu_iterator_create (mu_iterator_t *piterator, void *owner)
31 {
32   mu_iterator_t iterator;
33   if (piterator == NULL)
34     return MU_ERR_OUT_PTR_NULL;
35   if (owner == NULL)
36     return EINVAL;
37   iterator = calloc (1, sizeof (*iterator));
38   if (iterator == NULL)
39     return ENOMEM;
40   iterator->owner = owner;
41   *piterator = iterator;
42   return 0;
43 }
44 
45 int
mu_iterator_set_first(mu_iterator_t itr,int (* first)(void *))46 mu_iterator_set_first (mu_iterator_t itr, int (*first) (void *))
47 {
48   if (!itr)
49     return EINVAL;
50   itr->first = first;
51   return 0;
52 }
53 
54 int
mu_iterator_set_next(mu_iterator_t itr,int (* next)(void *))55 mu_iterator_set_next (mu_iterator_t itr, int (*next) (void *))
56 {
57   if (!itr)
58     return EINVAL;
59   itr->next = next;
60   return 0;
61 }
62 
63 int
mu_iterator_set_getitem(mu_iterator_t itr,int (* getitem)(void *,void **,const void **))64 mu_iterator_set_getitem (mu_iterator_t itr,
65 			 int (*getitem) (void *, void **, const void **))
66 {
67   if (!itr)
68     return EINVAL;
69   itr->getitem = getitem;
70   return 0;
71 }
72 
73 int
mu_iterator_set_finished_p(mu_iterator_t itr,int (* finished_p)(void *))74 mu_iterator_set_finished_p (mu_iterator_t itr, int (*finished_p) (void *))
75 {
76   if (!itr)
77     return EINVAL;
78   itr->finished_p = finished_p;
79   return 0;
80 }
81 
82 int
mu_iterator_set_delitem(mu_iterator_t itr,int (* delitem)(void *,void *))83 mu_iterator_set_delitem (mu_iterator_t itr,
84 			 int (*delitem) (void *, void *))
85 {
86   if (!itr)
87     return EINVAL;
88   itr->delitem = delitem;
89   return 0;
90 }
91 
92 int
mu_iterator_set_itrctl(mu_iterator_t itr,int (* itrctl)(void *,enum mu_itrctl_req,void *))93 mu_iterator_set_itrctl (mu_iterator_t itr,
94 			int (*itrctl) (void *,
95 				       enum mu_itrctl_req,
96 				       void *))
97 {
98   if (!itr)
99     return EINVAL;
100   itr->itrctl = itrctl;
101   return 0;
102 }
103 
104 int
mu_iterator_set_dataptr(mu_iterator_t itr,void * (* dataptr)(void *))105 mu_iterator_set_dataptr (mu_iterator_t itr, void *(*dataptr) (void *))
106 {
107   if (!itr)
108     return EINVAL;
109   itr->dataptr = dataptr;
110   return 0;
111 }
112 
113 int
mu_iterator_set_destroy(mu_iterator_t itr,int (* destroy)(mu_iterator_t,void *))114 mu_iterator_set_destroy (mu_iterator_t itr, int (*destroy) (mu_iterator_t, void *))
115 {
116   if (!itr)
117     return EINVAL;
118   itr->destroy = destroy;
119   return 0;
120 }
121 
122 int
mu_iterator_set_dup(mu_iterator_t itr,int (* dup)(void ** ptr,void * data))123 mu_iterator_set_dup (mu_iterator_t itr, int (*dup) (void **ptr, void *data))
124 {
125   if (!itr)
126     return EINVAL;
127   itr->dup = dup;
128   return 0;
129 }
130 
131 
132 
133 int
mu_iterator_dup(mu_iterator_t * piterator,mu_iterator_t orig)134 mu_iterator_dup (mu_iterator_t *piterator, mu_iterator_t orig)
135 {
136   mu_iterator_t iterator;
137   int status;
138 
139   if (piterator == NULL)
140     return MU_ERR_OUT_PTR_NULL;
141   if (orig == NULL)
142     return EINVAL;
143 
144   status = mu_iterator_create (&iterator, orig->owner);
145   if (status)
146     return status;
147 
148   status = orig->dup (&iterator->owner, orig->owner);
149   if (status)
150     {
151       free (iterator);
152       return status;
153     }
154   iterator->is_advanced = orig->is_advanced;
155   iterator->dup = orig->dup;
156   iterator->destroy = orig->destroy;
157   iterator->first = orig->first;
158   iterator->next = orig->next;
159   iterator->getitem = orig->getitem;
160   iterator->delitem = orig->delitem;
161   iterator->finished_p = orig->finished_p;
162   iterator->itrctl = orig->itrctl;
163 
164   *piterator = iterator;
165   return 0;
166 }
167 
168 void
mu_iterator_destroy(mu_iterator_t * piterator)169 mu_iterator_destroy (mu_iterator_t *piterator)
170 {
171   if (!piterator || !*piterator)
172     return;
173 
174   if ((*piterator)->destroy)
175     (*piterator)->destroy (*piterator, (*piterator)->owner);
176 
177   free (*piterator);
178   *piterator = NULL;
179 }
180 
181 int
mu_iterator_first(mu_iterator_t iterator)182 mu_iterator_first (mu_iterator_t iterator)
183 {
184   iterator->is_advanced = 0;
185   return iterator->first (iterator->owner);
186 }
187 
188 int
mu_iterator_next(mu_iterator_t iterator)189 mu_iterator_next (mu_iterator_t iterator)
190 {
191   int status = 0;
192   if (!iterator->is_advanced)
193     status = iterator->next (iterator->owner);
194   iterator->is_advanced = 0;
195   return status;
196 }
197 
198 int
mu_iterator_skip(mu_iterator_t iterator,ssize_t count)199 mu_iterator_skip (mu_iterator_t iterator, ssize_t count)
200 {
201   int status;
202   if (count < 0)
203     return ENOSYS; /* Need prev method */
204   while (count--)
205     if ((status = mu_iterator_next (iterator)))
206       break;
207   return status;
208 }
209 
210 int
mu_iterator_skip_while(mu_iterator_t iterator,int (* pred)(void *,void *),void * data)211 mu_iterator_skip_while (mu_iterator_t iterator,
212 			int (*pred) (void *, void *),
213 			void *data)
214 {
215   int status;
216   if (!iterator || !pred)
217     return EINVAL;
218   do
219     {
220       if ((status = mu_iterator_next (iterator)) == 0)
221 	{
222 	  void *item;
223 	  if ((status = mu_iterator_current  (iterator, &item)) == 0)
224 	    if (!pred (item, data))
225 	      break;
226 	}
227     }
228   while (status == 0);
229 
230   return status;
231 }
232 
233 int
mu_iterator_skip_until(mu_iterator_t iterator,int (* pred)(void *,void *),void * data)234 mu_iterator_skip_until (mu_iterator_t iterator,
235 			int (*pred) (void *, void *),
236 			void *data)
237 {
238   int status;
239   if (!iterator || !pred)
240     return EINVAL;
241   do
242     {
243       if ((status = mu_iterator_next (iterator)) == 0)
244 	{
245 	  void *item;
246 	  if ((status = mu_iterator_current  (iterator, &item)) == 0)
247 	    if (pred (item, data))
248 	      break;
249 	}
250     }
251   while (status == 0);
252 
253   return status;
254 }
255 
256 
257 int
mu_iterator_current(mu_iterator_t iterator,void ** pitem)258 mu_iterator_current (mu_iterator_t iterator, void **pitem)
259 {
260   return mu_iterator_current_kv (iterator, NULL, pitem);
261 }
262 
263 int
mu_iterator_current_kv(mu_iterator_t iterator,const void ** pkey,void ** pitem)264 mu_iterator_current_kv (mu_iterator_t iterator,
265 			const void **pkey, void **pitem)
266 {
267   void *ptr;
268   int rc = iterator->getitem (iterator->owner, &ptr, pkey);
269   if (rc == 0)
270     {
271       if (iterator->dataptr)
272 	*pitem = iterator->dataptr (ptr);
273       else
274 	*pitem = ptr;
275     }
276   return rc;
277 }
278 
279 int
mu_iterator_is_done(mu_iterator_t iterator)280 mu_iterator_is_done (mu_iterator_t iterator)
281 {
282   if (iterator == NULL)
283     return 1;
284   return iterator->finished_p (iterator->owner);
285 }
286 
287 int
iterator_get_owner(mu_iterator_t iterator,void ** powner)288 iterator_get_owner (mu_iterator_t iterator, void **powner)
289 {
290   if (!iterator)
291     return EINVAL;
292   if (!powner)
293     return MU_ERR_OUT_PTR_NULL;
294   *powner = iterator->owner;
295   return 0;
296 }
297 
298 void
mu_iterator_delitem(mu_iterator_t iterator,void * itm)299 mu_iterator_delitem (mu_iterator_t iterator, void *itm)
300 {
301   for (; iterator; iterator = iterator->next_itr)
302     {
303       if (iterator->delitem)
304 	{
305 	  switch (iterator->delitem (iterator->owner, itm))
306 	    {
307 	    case MU_ITR_DELITEM_NEXT:
308 	      iterator->next (iterator->owner);
309 	    case MU_ITR_DELITEM_ADVANCE:
310 	      iterator->is_advanced++;
311 	    }
312 	}
313     }
314 }
315 
316 int
mu_iterator_attach(mu_iterator_t * root,mu_iterator_t iterator)317 mu_iterator_attach (mu_iterator_t *root, mu_iterator_t iterator)
318 {
319   iterator->next_itr = *root;
320   *root = iterator;
321   return 0;
322 }
323 
324 int
mu_iterator_detach(mu_iterator_t * root,mu_iterator_t iterator)325 mu_iterator_detach (mu_iterator_t *root, mu_iterator_t iterator)
326 {
327   mu_iterator_t itr, prev;
328 
329   for (itr = *root, prev = NULL; itr; prev = itr, itr = itr->next_itr)
330     if (iterator == itr)
331       break;
332 
333   if (itr)
334     {
335       if (prev)
336 	prev->next_itr = itr->next_itr;
337       else
338 	*root = itr->next_itr;
339     }
340 
341   return 0;
342 }
343 
344 int
mu_iterator_ctl(mu_iterator_t iterator,enum mu_itrctl_req req,void * arg)345 mu_iterator_ctl (mu_iterator_t iterator, enum mu_itrctl_req req, void *arg)
346 {
347   if (!iterator)
348     return EINVAL;
349   if (!iterator->itrctl)
350     return ENOSYS;
351   return iterator->itrctl (iterator->owner, req, arg);
352 }
353