1 /*
2 Copyright (C) 1999-2004 IC & S dbmail@ic-s.nl
3 Copyright (c) 2004-2012 NFG Net Facilities Group BV support@nfg.nl
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later
9 version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include "dbmail.h"
23
24 /*
25 * pool based list implementation
26 *
27 */
28
29 #define T List_T
30
31 struct T {
32 Mempool_T pool;
33 T prev;
34 T next;
35 void *data;
36 };
37
_alloc_list(Mempool_T pool)38 T _alloc_list(Mempool_T pool)
39 {
40 assert(pool);
41 T L;
42 L = mempool_pop(pool, sizeof(*L));
43 L->pool = pool;
44 return L;
45 }
46
p_list_new(Mempool_T pool)47 T p_list_new(Mempool_T pool)
48 {
49 return _alloc_list(pool);
50 }
51
52 #define ISEMPTY(l) (l->next == NULL && \
53 l->prev == NULL && \
54 l->data == NULL)
p_list_append(T L,void * data)55 T p_list_append(T L, void *data)
56 {
57 assert(L);
58 if ISEMPTY(L) {
59 L->data = data;
60 return L;
61 }
62 L = p_list_last(L);
63 T new = _alloc_list(L->pool);
64 new->data = data;
65 new->prev = L;
66 L->next = new;
67 return new;
68 }
69
p_list_prepend(T L,void * data)70 T p_list_prepend(T L, void *data)
71 {
72 assert(L);
73 if ISEMPTY(L) {
74 L->data = data;
75 return L;
76 }
77 L = p_list_first(L);
78 T new = _alloc_list(L->pool);
79 new->data = data;
80 new->next = L;
81 L->prev = new;
82 return new;
83 }
84
p_list_last(T L)85 T p_list_last(T L)
86 {
87 assert(L);
88 T last = L;
89 while (last->next)
90 last = last->next;
91 return last;
92 }
93
p_list_first(T L)94 T p_list_first(T L)
95 {
96 assert(L);
97 T first = L;
98 while (first->prev)
99 first = first->prev;
100 return first;
101 }
102
p_list_previous(T L)103 T p_list_previous(T L)
104 {
105 assert(L);
106 return L->prev;
107 }
108
p_list_next(T L)109 T p_list_next(T L)
110 {
111 assert(L);
112 return L->next;
113 }
114
p_list_length(T L)115 size_t p_list_length(T L)
116 {
117 size_t length = 0;
118 if (ISEMPTY(L))
119 return length;
120 while (L) {
121 length++;
122 L = L->next;
123 }
124 return length;
125 }
126
p_list_data(T L)127 void * p_list_data(T L)
128 {
129 assert(L);
130 return L->data;
131 }
132
p_list_free(T * L)133 void p_list_free(T *L)
134 {
135 T l = *L;
136 Mempool_T pool = l->pool;
137 while (l) {
138 T ll = l;
139 l = ll->next;
140 mempool_push(pool, ll, sizeof(*ll));
141 }
142 }
143
p_list_remove(T L,T E)144 T p_list_remove(T L, T E)
145 {
146 if (E) {
147 L = p_list_first(L);
148 if (E->prev)
149 E->prev->next = E->next;
150 if (E->next)
151 E->next->prev = E->prev;
152
153 if (L == E)
154 L = L->next;
155
156 E->next = NULL;
157 E->prev = NULL;
158 }
159
160 return L;
161 }
162
163 #undef T
164
165
166 /* GList helper functions */
g_list_destroy(GList * l)167 void g_list_destroy(GList *l)
168 {
169 if (! l) return;
170 l = g_list_first(l);
171 g_list_foreach(l,(GFunc)g_free,NULL);
172
173 l = g_list_first(l);
174 g_list_free(l);
175 }
176
177
178
179
180 /*
181 * return a list of strings (a,b,c,..N)
182 */
183
184 //FIXME: this needs some cleaning up:
g_list_slices(GList * list,unsigned limit)185 GList *g_list_slices(GList *list, unsigned limit)
186 {
187 unsigned i;
188 GList *new = NULL;
189 GString *slice;
190
191 list = g_list_first(list);
192
193 while(list) {
194 slice = g_string_new("");
195 g_string_append_printf(slice,"%s",(gchar *)list->data);
196 for (i=1; i<limit; i++) {
197 list = g_list_next(list);
198 if (!list)
199 break;
200 g_string_append_printf(slice,",%s", (gchar *)list->data);
201 }
202 new = g_list_append_printf(new, "%s", slice->str);
203 g_string_free(slice,TRUE);
204 if (! g_list_next(list))
205 break;
206 list = g_list_next(list);
207 }
208
209 return new;
210 }
211
g_list_slices_u64(GList * list,unsigned limit)212 GList *g_list_slices_u64(GList *list, unsigned limit)
213 {
214 unsigned i;
215 GList *new = NULL;
216 GString *slice;
217
218 list = g_list_first(list);
219 while(list) {
220 slice = g_string_new("");
221 g_string_append_printf(slice,"%" PRIu64 "",*(uint64_t *)list->data);
222 for (i=1; i<limit; i++) {
223 if (! g_list_next(list))
224 break;
225 list = g_list_next(list);
226 g_string_append_printf(slice,",%" PRIu64 "", *(uint64_t *)list->data);
227 }
228 new = g_list_append_printf(new, "%s", slice->str);
229 g_string_free(slice,TRUE);
230 if (! g_list_next(list))
231 break;
232 list = g_list_next(list);
233 }
234
235 return new;
236 }
237
g_list_dedup(GList * list,GCompareFunc compare_func,int freeitems)238 GList *g_list_dedup(GList *list, GCompareFunc compare_func, int freeitems)
239 {
240 char *lastdata = NULL;
241
242 list = g_list_first(list);
243 while (list) {
244 if (lastdata && list->data && compare_func(lastdata, list->data) == 0) {
245 if (freeitems)
246 g_free(list->data);
247 list = g_list_delete_link(g_list_previous(list), list);
248 } else {
249 lastdata = (char *)list->data;
250 }
251 if (! g_list_next(list))
252 break;
253 list = g_list_next(list);
254 }
255
256 return g_list_first(list);
257 }
258
g_list_join(GList * list,const gchar * sep)259 GString * g_list_join(GList * list, const gchar * sep)
260 {
261 GString *string = g_string_new("");
262 if (sep == NULL)
263 sep="";
264 if (list == NULL)
265 return string;
266 list = g_list_first(list);
267 g_string_append_printf(string,"%s",(gchar *)list->data);
268 while((list = g_list_next(list))) {
269 g_string_append_printf(string,"%s%s", sep,(gchar *)list->data);
270 if (! g_list_next(list))
271 break;
272 }
273 return string;
274 }
g_list_join_u64(GList * list,const gchar * sep)275 GString * g_list_join_u64(GList * list, const gchar * sep)
276 {
277 uint64_t *token;
278 GString *string = g_string_new("");
279 if (sep == NULL)
280 sep="";
281 if (list == NULL)
282 return string;
283 list = g_list_first(list);
284 token = (uint64_t*)list->data;
285 g_string_append_printf(string,"%" PRIu64 "",*token);
286 while((list = g_list_next(list))) {
287 token = (uint64_t*)list->data;
288 g_string_append_printf(string,"%s%" PRIu64 "", sep,*token);
289 if (! g_list_next(list))
290 break;
291 }
292 return string;
293 }
294
295 /*
296 * append a formatted string to a GList
297 */
g_list_append_printf(GList * list,const char * format,...)298 GList * g_list_append_printf(GList * list, const char * format, ...)
299 {
300 va_list ap, cp;
301 va_start(ap, format);
302 va_copy(cp, ap);
303 list = g_list_append(list, g_strdup_vprintf(format, cp));
304 va_end(cp);
305 va_end(ap);
306 return list;
307 }
308
309
310 /*
311 * a and b are lists of char keys
312 * matching is done using func
313 * for each key in b, keys are copied into or removed from a and freed
314 */
315
g_list_merge(GList ** a,GList * b,int condition,GCompareFunc func)316 void g_list_merge(GList **a, GList *b, int condition, GCompareFunc func)
317 {
318 gchar *t;
319
320 b = g_list_first(b);
321
322 if (condition == IMAPFA_ADD) {
323 while (b) {
324 t = (gchar *)b->data;
325 if (! g_list_find_custom(*(GList **)a, t, (GCompareFunc)func))
326 *(GList **)a = g_list_append(*(GList **)a, g_strdup(t));
327 if (! g_list_next(b))
328 break;
329 b = g_list_next(b);
330 }
331 }
332 if (condition == IMAPFA_REMOVE) {
333 GList *el = NULL;
334
335 while (b) {
336 *(GList **)a = g_list_first(*(GList **)a);
337 t = (gchar *)b->data;
338 if ((el = g_list_find_custom(*(GList **)a, t, (GCompareFunc)func)) != NULL) {
339 *(GList **)a = g_list_remove_link(*(GList **)a, el);
340 g_list_destroy(el);
341 }
342
343 if (! g_list_next(b))
344 break;
345 b = g_list_next(b);
346 }
347 }
348 if (condition == IMAPFA_REPLACE) {
349 g_list_destroy(*(GList **)a);
350 *(GList **)a = NULL;
351
352 while (b) {
353 t = (gchar *)b->data;
354 *(GList **)a = g_list_append(*(GList **)a, g_strdup(t));
355 if (! g_list_next(b))
356 break;
357 b = g_list_next(b);
358 }
359 }
360
361
362 }
363
364
365