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