1 /* libcomps - C alternative to yum.comps library
2  * Copyright (C) 2013 Jindrich Luza
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to  Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
17  * USA
18  */
19 
20 #include "comps_hslist.h"
21 #include "comps_set.h"
22 
23 #include <stdlib.h>
comps_hslist_create()24 COMPS_HSList * comps_hslist_create() {
25     COMPS_HSList *ret;
26     ret =  malloc(sizeof(COMPS_HSList));
27     if (!ret) {
28         return NULL;
29     }
30     return ret;
31 }
32 
comps_hslist_init(COMPS_HSList * hslist,void * (* data_constructor)(void * data),void * (* data_cloner)(void * data),void (* data_destructor)(void * data))33 void comps_hslist_init(COMPS_HSList * hslist,
34                             void*(*data_constructor)(void* data),
35                             void*(*data_cloner)(void* data),
36                             void(*data_destructor)(void* data)) {
37     if (hslist == NULL) {
38         return;
39     }
40     hslist->data_constructor = data_constructor;
41     hslist->data_destructor = data_destructor;
42     hslist->data_cloner = data_cloner;
43     hslist->first = NULL;
44     hslist->last = NULL;
45 }
46 
comps_hslist_append(COMPS_HSList * hslist,void * data,unsigned construct)47 void comps_hslist_append(COMPS_HSList * hslist, void * data, unsigned construct) {
48     COMPS_HSListItem * it;
49 
50     if (hslist == NULL)
51         return;
52     if ((it = malloc(sizeof(*it))) == NULL)
53         return;
54     if (construct && hslist->data_constructor) {
55         it->data = hslist->data_constructor(data);
56     } else {
57         it->data = data;
58     }
59     it->next = NULL;
60     if (hslist->last == NULL) {
61         hslist->last = it;
62         hslist->first = it;
63     } else {
64         hslist->last->next = it;
65         hslist->last = hslist->last->next;
66     }
67 }
68 
comps_hslist_insert_after(COMPS_HSList * hslist,COMPS_HSListItem * item,void * data,unsigned construct)69 void comps_hslist_insert_after(COMPS_HSList * hslist, COMPS_HSListItem *item,
70                                void *data, unsigned construct) {
71     COMPS_HSListItem * it;
72     void * ndata;
73 
74     if (hslist == NULL || item == NULL)
75         return;
76     if ((it = malloc(sizeof(*it))) == NULL)
77         return;
78     if (construct && hslist->data_constructor) {
79         ndata = hslist->data_constructor(data);
80     } else {
81         ndata = data;
82     }
83     it->data = ndata;
84     it->next = item->next;
85     item->next = it;
86     if (item == hslist->last) {
87         //printf("inserting after last\n");
88         hslist->last = it;
89     }
90 }
comps_hslist_insert_at(COMPS_HSList * hslist,int pos,void * data,unsigned construct)91 int comps_hslist_insert_at(COMPS_HSList * hslist, int pos,
92                                void *data, unsigned construct) {
93     COMPS_HSListItem *it, *oldit, *newit;
94     int n;
95 
96     if (hslist == NULL)
97         return 0;
98     if ((newit = malloc(sizeof(*newit))) == NULL)
99         return 0;
100     if (construct && hslist->data_constructor) {
101         newit->data = hslist->data_constructor(data);
102     } else {
103         newit->data = data;
104     }
105     oldit=NULL;
106     for (n=0, it = hslist->first; n != pos && it != NULL; n++, it = it->next) {
107         oldit = it;
108     }
109     if (n == 0 && pos == 0) {
110         newit->next = hslist->first;
111         hslist->first = newit;
112         if (hslist->last == NULL)
113             hslist->last = newit;
114     } else if (n == pos) {
115         newit->next = oldit->next;
116         oldit->next = newit;
117     } else {
118         if (hslist->data_destructor)
119             hslist->data_destructor(newit->data);
120         free(newit);
121     }
122     return 1;
123 }
124 
comps_hslist_prepend(COMPS_HSList * hslist,void * data,unsigned construct)125 void comps_hslist_prepend(COMPS_HSList * hslist, void *data, unsigned construct) {
126     COMPS_HSListItem * it;
127     void * ndata;
128 
129     if (hslist == NULL)
130         return;
131     if ((it = malloc(sizeof(*it))) == NULL)
132         return;
133     if (construct && hslist->data_constructor) {
134         ndata = hslist->data_constructor(data);
135     } else {
136         ndata = data;
137     }
138     it->data = ndata;
139     it->next = hslist->first;
140     hslist->first = it;
141 }
142 
comps_hslist_shift(COMPS_HSList * hslist)143 void* comps_hslist_shift(COMPS_HSList * hslist) {
144     void * data;
145     COMPS_HSListItem *it;
146 
147     if (hslist == NULL || hslist->first == NULL) {
148         //printf("ret null %p\n", hslist->first);
149         return NULL;
150     }
151     it = hslist->first;
152     data = hslist->first->data;
153     hslist->first = hslist->first->next;
154     if (hslist->first == NULL)
155         hslist->last=NULL;
156     free(it);
157     return data;
158 }
159 
comps_hslist_pop(COMPS_HSList * hslist)160 void* comps_hslist_pop(COMPS_HSList * hslist) {
161     void * data;
162     COMPS_HSListItem *it, *it2;
163 
164     if (hslist == NULL || hslist->first == NULL)
165         return NULL;
166     it2 = NULL;
167     for (it = hslist->first; it != hslist->last; it2=it, it = it->next);
168 
169     if (!it2) {
170         hslist->last = NULL;
171         hslist->first = NULL;
172     } else {
173         hslist->last = it2;
174         it2->next = NULL;
175     }
176     data = it->data;
177     free(it);
178     return data;
179 }
180 
comps_hslist_destroy_v(void ** hslist)181 inline void comps_hslist_destroy_v(void ** hslist) {
182     comps_hslist_destroy((COMPS_HSList**) hslist);
183 }
184 
comps_hslist_destroy(COMPS_HSList ** hslist)185 void comps_hslist_destroy(COMPS_HSList ** hslist) {
186     COMPS_HSListItem *it,*oldit;
187     unsigned int x;
188     if (*hslist == NULL) return;
189     oldit = (*hslist)->first;
190     it = (oldit)?oldit->next:NULL;
191     for (x=0 ;it != NULL; it=it->next, x++) {
192         if ((*hslist)->data_destructor != NULL)
193             (*hslist)->data_destructor(oldit->data);
194         free(oldit);
195         oldit = it;
196     }
197     if (oldit) {
198         if ((*hslist)->data_destructor != NULL)
199             (*hslist)->data_destructor(oldit->data);
200         free(oldit);
201     }
202     free(*hslist);
203     *hslist = NULL;
204 }
205 
comps_hslist_remove(COMPS_HSList * hslist,COMPS_HSListItem * it)206 void comps_hslist_remove(COMPS_HSList * hslist,
207                               COMPS_HSListItem * it) {
208     COMPS_HSListItem *itx, *itprev=NULL;
209     if (it == NULL) return;
210     for (itx = hslist->first; itx != NULL && itx != it; itx = itx->next) {
211         itprev = itx;
212     }
213     if (itx != it)
214         return;
215     if (itprev == NULL) {
216         if (hslist->first == hslist->last)
217             hslist->last = hslist->first->next;
218         hslist->first = hslist->first->next;
219     } else {
220         itprev->next = it->next;
221         if (it == hslist->last) {
222             if (hslist->first == hslist->last)
223                 hslist->first = itprev;
224             hslist->last = itprev;
225         }
226     }
227 }
228 
comps_hslist_data_at(COMPS_HSList * hlist,unsigned int index)229 void* comps_hslist_data_at(COMPS_HSList * hlist, unsigned int index)
230 {
231     unsigned int i=0;
232     COMPS_HSListItem * itx;
233     for (itx = hlist->first; itx != NULL && index != i; itx = itx->next, i++);
234     if (itx == NULL)
235         return itx;
236     else
237         return itx->data;
238 }
239 
comps_hslist_clone(COMPS_HSList * hslist)240 COMPS_HSList* comps_hslist_clone(COMPS_HSList * hslist) {
241     COMPS_HSList *ret;
242     COMPS_HSListItem *it;
243 
244     ret = comps_hslist_create();
245     comps_hslist_init(ret, hslist->data_constructor,
246                            hslist->data_cloner,
247                            hslist->data_destructor);
248     for (it = hslist->first; it != NULL; it = it->next) {
249         comps_hslist_append(ret, hslist->data_cloner(it->data), 0);
250     }
251     return ret;
252 }
253 
comps_hslist_clear(COMPS_HSList * hslist)254 void comps_hslist_clear(COMPS_HSList * hslist) {
255     COMPS_HSListItem *it,*oldit;
256     if (hslist == NULL) return;
257     oldit = hslist->first;
258     it = (oldit)?oldit->next:NULL;
259     for (;it != NULL; it=it->next) {
260         if (hslist->data_destructor != NULL)
261             hslist->data_destructor(oldit->data);
262         free(oldit);
263         oldit = it;
264     }
265     if (oldit) {
266         if (hslist->data_destructor != NULL)
267             hslist->data_destructor(oldit->data);
268         free(oldit);
269     }
270     hslist->first = NULL;
271     hslist->last = NULL;
272 }
273 
comps_hslist_values_equal(COMPS_HSList * hlist1,COMPS_HSList * hlist2,char (* cmpf)(void *,void *))274 unsigned comps_hslist_values_equal(COMPS_HSList *hlist1, COMPS_HSList *hlist2,
275                                    char (*cmpf)(void*, void*)) {
276     COMPS_HSListItem *it, *it2;
277     for (it = hlist1->first, it2 = hlist2->first; it != NULL && it2 != NULL;
278         it = it->next, it2 = it2->next) {
279         if (!cmpf(it->data, it2->data))
280             return 0;
281     }
282     if (it != NULL || it2 != NULL)
283         return 0;
284     return 1;
285 }
286 
comps_hslist_unique(COMPS_HSList * hlist,char (* cmpf)(void *,void *))287 void comps_hslist_unique(COMPS_HSList *hlist, char (*cmpf)(void*, void*)) {
288     COMPS_Set *set;
289     COMPS_HSListItem *it, *it2;
290 
291     if (hlist == NULL) return;
292 
293     set = comps_set_create();
294     comps_set_init(set, NULL, NULL, NULL, cmpf);
295     it2 = NULL;
296     for (it = hlist->first; it != NULL; it2 = it, it = it->next) {
297         if (!comps_set_in(set, it->data)) {
298             comps_set_add(set, it->data);
299         } else {
300             hlist->data_destructor(it->data);
301         }
302         free(it2);
303     }
304     free(it2);
305     hlist->first = set->data->first;
306     hlist->last = set->data->last;
307     free(set->data);
308     free(set);
309 }
310