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 <stdlib.h>
23 #include <string.h>
24 #include <mailutils/sys/list.h>
25 #include <mailutils/sys/iterator.h>
26 #include <mailutils/errno.h>
27
28 /* Iterator interface */
29
30 struct list_iterator
31 {
32 mu_list_t list;
33 struct list_data *cur;
34 int backwards; /* true if iterating backwards */
35 };
36
37 static int
first(void * owner)38 first (void *owner)
39 {
40 struct list_iterator *itr = owner;
41 if (itr->backwards)
42 itr->cur = itr->list->head.prev;
43 else
44 itr->cur = itr->list->head.next;
45 return 0;
46 }
47
48 static int
next(void * owner)49 next (void *owner)
50 {
51 struct list_iterator *itr = owner;
52 if (itr->backwards)
53 itr->cur = itr->cur->prev;
54 else
55 itr->cur = itr->cur->next;
56 return 0;
57 }
58
59 static int
getitem(void * owner,void ** pret,const void ** pkey)60 getitem (void *owner, void **pret, const void **pkey)
61 {
62 struct list_iterator *itr = owner;
63 *pret = itr->cur->item;
64 if (pkey)
65 *pkey = NULL;
66 return 0;
67 }
68
69 static int
finished_p(void * owner)70 finished_p (void *owner)
71 {
72 struct list_iterator *itr = owner;
73 return itr->cur == &itr->list->head;
74 }
75
76 static int
destroy(mu_iterator_t iterator,void * data)77 destroy (mu_iterator_t iterator, void *data)
78 {
79 struct list_iterator *itr = data;
80 mu_iterator_detach (&itr->list->itr, iterator);
81 free (data);
82 return 0;
83 }
84
85 static int
delitem(void * owner,void * item)86 delitem (void *owner, void *item)
87 {
88 struct list_iterator *itr = owner;
89 return itr->cur == item ? MU_ITR_DELITEM_NEXT : MU_ITR_DELITEM_NOTHING;
90 }
91
92 static int
list_data_dup(void ** ptr,void * owner)93 list_data_dup (void **ptr, void *owner)
94 {
95 *ptr = malloc (sizeof (struct list_iterator));
96 if (*ptr == NULL)
97 return ENOMEM;
98 memcpy (*ptr, owner, sizeof (struct list_iterator));
99 return 0;
100 }
101
102 static int
list_itrctl(void * owner,enum mu_itrctl_req req,void * arg)103 list_itrctl (void *owner, enum mu_itrctl_req req, void *arg)
104 {
105 struct list_iterator *itr = owner;
106 mu_list_t list = itr->list;
107 struct list_data *ptr;
108
109 switch (req)
110 {
111 case mu_itrctl_tell:
112 /* Return current position in the object */
113 if (itr->cur == NULL)
114 return MU_ERR_NOENT;
115 else
116 {
117 size_t count;
118
119 for (count = 0, ptr = list->head.next; ptr != &list->head;
120 ptr = ptr->next, count++)
121 {
122 if (ptr == itr->cur)
123 {
124 *(size_t*)arg = count;
125 return 0;
126 }
127 }
128 return MU_ERR_NOENT;
129 }
130 break;
131
132 case mu_itrctl_delete:
133 case mu_itrctl_delete_nd:
134 /* Delete current element */
135 if (itr->cur == NULL)
136 return MU_ERR_NOENT;
137 else
138 {
139 struct list_data *prev;
140
141 ptr = itr->cur;
142 prev = ptr->prev;
143
144 mu_iterator_delitem (list->itr, ptr);
145 prev->next = ptr->next;
146 ptr->next->prev = prev;
147 if (req == mu_itrctl_delete)
148 DESTROY_ITEM (list, ptr);
149 free (ptr);
150 list->count--;
151 }
152 break;
153
154 case mu_itrctl_replace:
155 case mu_itrctl_replace_nd:
156 /* Replace current element */
157 if (itr->cur == NULL)
158 return MU_ERR_NOENT;
159 if (!arg)
160 return EINVAL;
161 ptr = itr->cur;
162 if (req == mu_itrctl_replace)
163 DESTROY_ITEM (list, ptr);
164 ptr = itr->cur;
165 ptr->item = arg;
166 break;
167
168 case mu_itrctl_insert:
169 /* Insert new element in the current position */
170 if (itr->cur == NULL)
171 return MU_ERR_NOENT;
172 if (!arg)
173 return EINVAL;
174 return _mu_list_insert_item (list, itr->cur, arg, 0);
175
176 case mu_itrctl_insert_list:
177 /* Insert a list of elements */
178 if (itr->cur == NULL)
179 return MU_ERR_NOENT;
180 if (!arg)
181 return EINVAL;
182 else
183 {
184 mu_list_t new_list = arg;
185 _mu_list_insert_sublist (list, itr->cur,
186 new_list->head.next, new_list->head.prev,
187 new_list->count,
188 0);
189 _mu_list_clear (new_list);
190 }
191 break;
192
193 case mu_itrctl_qry_direction:
194 if (!arg)
195 return EINVAL;
196 else
197 *(int*)arg = itr->backwards;
198 break;
199
200 case mu_itrctl_set_direction:
201 if (!arg)
202 return EINVAL;
203 else
204 itr->backwards = !!*(int*)arg;
205 break;
206
207 case mu_itrctl_count:
208 if (!arg)
209 return EINVAL;
210 return mu_list_count (itr->list, arg);
211
212 default:
213 return ENOSYS;
214 }
215 return 0;
216 }
217
218 int
mu_list_get_iterator(mu_list_t list,mu_iterator_t * piterator)219 mu_list_get_iterator (mu_list_t list, mu_iterator_t *piterator)
220 {
221 mu_iterator_t iterator;
222 int status;
223 struct list_iterator *itr;
224
225 if (!list)
226 return EINVAL;
227
228 itr = calloc (1, sizeof *itr);
229 if (!itr)
230 return ENOMEM;
231 itr->list = list;
232 itr->cur = NULL;
233
234 status = mu_iterator_create (&iterator, itr);
235 if (status)
236 {
237 free (itr);
238 return status;
239 }
240
241 mu_iterator_set_first (iterator, first);
242 mu_iterator_set_next (iterator, next);
243 mu_iterator_set_getitem (iterator, getitem);
244 mu_iterator_set_finished_p (iterator, finished_p);
245 mu_iterator_set_delitem (iterator, delitem);
246 mu_iterator_set_destroy (iterator, destroy);
247 mu_iterator_set_dup (iterator, list_data_dup);
248 mu_iterator_set_itrctl (iterator, list_itrctl);
249
250 mu_iterator_attach (&list->itr, iterator);
251
252 *piterator = iterator;
253 return 0;
254 }
255