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_doccategory.h"
21 #include "comps_set.h"
22 
comps_doccategory_create(COMPS_DocCategory * category,COMPS_Object ** args)23 void comps_doccategory_create(COMPS_DocCategory *category, COMPS_Object **args) {
24     (void)args;
25     category->properties = COMPS_OBJECT_CREATE(COMPS_ObjDict, NULL);
26     category->name_by_lang = COMPS_OBJECT_CREATE(COMPS_ObjDict, NULL);
27     category->desc_by_lang = COMPS_OBJECT_CREATE(COMPS_ObjDict, NULL);
28     category->group_ids = COMPS_OBJECT_CREATE(COMPS_ObjList, NULL);
29 }
COMPS_CREATE_u(doccategory,COMPS_DocCategory)30 COMPS_CREATE_u(doccategory, COMPS_DocCategory)  /*comps_utils.h macro*/
31 
32 void comps_doccategory_copy(COMPS_DocCategory *category_dst,
33                             COMPS_DocCategory *category_src) {
34     category_dst->properties = (COMPS_ObjDict*)
35                                 COMPS_OBJECT_COPY(category_src->properties);
36     category_dst->name_by_lang = (COMPS_ObjDict*)
37                                 COMPS_OBJECT_COPY(category_src->name_by_lang);
38     category_dst->desc_by_lang = (COMPS_ObjDict*)
39                                 COMPS_OBJECT_COPY(category_src->desc_by_lang);
40     category_dst->group_ids = (COMPS_ObjList*)
41                                 COMPS_OBJECT_COPY(category_src->group_ids);
42 }
COMPS_COPY_u(doccategory,COMPS_DocCategory)43 COMPS_COPY_u(doccategory, COMPS_DocCategory)    /*comps_utils.h macro*/
44 
45 static void comps_doccategory_destroy(COMPS_DocCategory *category) {
46     COMPS_OBJECT_DESTROY(category->properties);
47     COMPS_OBJECT_DESTROY(category->name_by_lang);
48     COMPS_OBJECT_DESTROY(category->desc_by_lang);
49     COMPS_OBJECT_DESTROY(category->group_ids);
50 }
COMPS_DESTROY_u(doccategory,COMPS_DocCategory)51 COMPS_DESTROY_u(doccategory, COMPS_DocCategory) /*comps_utils.h macro*/
52 
53 COMPS_STRPROP_SETTER(category, COMPS_DocCategory, id) /*comps_utils.h macro*/
54 COMPS_STRPROP_SETTER(category, COMPS_DocCategory, name) /*comps_utils.h macro*/
55 COMPS_STRPROP_SETTER(category, COMPS_DocCategory, desc) /*comps_utils.h macro*/
56 COMPS_NUMPROP_SETTER(category, COMPS_DocCategory, display_order) /*comps_utils.h macro*/
57 
58 COMPS_PROP_GETTER(category, COMPS_DocCategory, id) /*comps_utils.h macro*/
59 COMPS_PROP_GETTER_OBJ(category, COMPS_DocCategory, id) /*comps_utils.h macro*/
60 COMPS_PROP_GETTER(category, COMPS_DocCategory, name) /*comps_utils.h macro*/
61 COMPS_PROP_GETTER(category, COMPS_DocCategory, desc) /*comps_utils.h macro*/
62 COMPS_PROP_GETTER(category, COMPS_DocCategory, display_order) /*comps_utils.h macro*/
63 
64 COMPS_DOCOBJ_GETOBJLIST(doccategory, COMPS_DocCategory, group_ids, group_ids)
65 COMPS_DOCOBJ_SETOBJLIST(doccategory, COMPS_DocCategory, group_ids, group_ids)
66 
67 COMPS_DOCOBJ_GETARCHES(doccategory, COMPS_DocCategory)/*comps_utils.h macro*/
68 COMPS_DOCOBJ_SETARCHES(doccategory, COMPS_DocCategory)/*comps_utils.h macro*/
69 
70 void comps_doccategory_add_groupid(COMPS_DocCategory *category,
71                                 COMPS_DocGroupId *gid) {
72 
73     if (category == NULL || gid == NULL) {
74         assert(0);
75         return;
76     }
77     if (category->group_ids == NULL) {
78         category->group_ids = COMPS_OBJECT_CREATE(COMPS_ObjList, NULL);
79     }
80     comps_objlist_append_x(category->group_ids, (COMPS_Object*)gid);
81 }
82 
comps_doccategory_cmp_u(COMPS_Object * cat1,COMPS_Object * cat2)83 signed char comps_doccategory_cmp_u(COMPS_Object *cat1, COMPS_Object *cat2) {
84     #define _cat1 ((COMPS_DocCategory*)cat1)
85     #define _cat2 ((COMPS_DocCategory*)cat2)
86 
87     if (!comps_object_cmp((COMPS_Object*)_cat1->properties,
88                           (COMPS_Object*)_cat2->properties)) {
89         //printf("Category properties cmp fail\n");
90         return 0;
91     }
92     if (!comps_object_cmp((COMPS_Object*)_cat1->name_by_lang,
93                           (COMPS_Object*)_cat2->name_by_lang)) {
94         //printf("Category name_by_lang cmp fail\n");
95         return 0;
96     }
97     if (!comps_object_cmp((COMPS_Object*)_cat1->desc_by_lang,
98                           (COMPS_Object*)_cat2->desc_by_lang)) {
99         //printf("Category desc_by_lang cmp fail\n");
100         return 0;
101     }
102     if (!comps_object_cmp((COMPS_Object*)_cat1->group_ids,
103                           (COMPS_Object*)_cat2->group_ids)) {
104         //printf("Category group_ids cmp fail\n");
105         return 0;
106     }
107     //printf("group category pass\n");
108     return 1;
109     #undef _cat1
110     #undef _cat2
111 }
112 
__comps_doccategory_idcmp(void * c1,void * c2)113 char __comps_doccategory_idcmp(void *c1, void *c2) {
114     COMPS_Object *obj1, *obj2;
115     char ret;
116     obj1 = comps_objdict_get(((COMPS_DocCategory*)c1)->properties, "id");
117     obj2 = comps_objdict_get(((COMPS_DocCategory*)c2)->properties, "id");
118     ret = comps_object_cmp(obj1, obj2);
119     COMPS_OBJECT_DESTROY(obj1);
120     COMPS_OBJECT_DESTROY(obj2);
121     return ret;
122 }
123 
comps_doccategory_union(COMPS_DocCategory * c1,COMPS_DocCategory * c2)124 COMPS_DocCategory* comps_doccategory_union(COMPS_DocCategory *c1,
125                                            COMPS_DocCategory *c2) {
126     COMPS_DocCategory *res;
127     COMPS_ObjListIt *it;
128     COMPS_Set *set;
129     COMPS_Object *obj;
130     void *data;
131     int index;
132 
133     res = COMPS_OBJECT_CREATE(COMPS_DocCategory,NULL);
134     COMPS_OBJECT_DESTROY(res->properties);
135 
136     res->properties = comps_objdict_union(c1->properties, c2->properties);
137     set = comps_set_create();
138     comps_set_init(set, NULL, NULL, &comps_object_destroy_v,
139                                     &__comps_docgroupid_cmp_set);
140     it = c1->group_ids?c1->group_ids->first:NULL;
141     for (; it != NULL; it = it->next) {
142         obj = comps_object_copy(it->comps_obj);
143         comps_set_add(set, (void*)comps_object_incref(obj));
144         comps_doccategory_add_groupid(res, (COMPS_DocGroupId*)obj);
145     }
146     it = c2->group_ids ? c2->group_ids->first : NULL;
147     for (; it != NULL; it = it->next) {
148         if ((data = comps_set_data_at(set, (void*)it->comps_obj)) != NULL) {
149             index = comps_objlist_index(res->group_ids, (COMPS_Object*)data);
150             comps_objlist_remove_at(res->group_ids, index);
151             comps_objlist_insert_at_x(res->group_ids, index,
152                                       comps_object_copy(it->comps_obj));
153         } else {
154             comps_doccategory_add_groupid(res, (COMPS_DocGroupId*)
155                                             comps_object_copy(it->comps_obj));
156         }
157     }
158     comps_set_destroy(&set);
159     COMPS_OBJECT_DESTROY(res->name_by_lang);
160     COMPS_OBJECT_DESTROY(res->desc_by_lang);
161     res->name_by_lang = comps_objdict_union(c1->name_by_lang, c2->name_by_lang);
162     res->desc_by_lang = comps_objdict_union(c1->desc_by_lang, c2->desc_by_lang);
163     return res;
164 }
165 
comps_doccategory_intersect(COMPS_DocCategory * c1,COMPS_DocCategory * c2)166 COMPS_DocCategory* comps_doccategory_intersect(COMPS_DocCategory *c1,
167                                          COMPS_DocCategory *c2) {
168     COMPS_DocCategory *res;
169     COMPS_ObjListIt *it;
170     COMPS_HSListItem *hsit;
171     COMPS_Set *set;
172 
173     COMPS_HSList *pairs1, *pairs2;
174 
175     res = COMPS_OBJECT_CREATE(COMPS_DocCategory, NULL);
176     set = comps_set_create();
177     comps_set_init(set, NULL, NULL, NULL, &comps_objrtree_paircmp);
178 
179     pairs1 = comps_objdict_pairs(c1->properties);
180     for (hsit = pairs1->first; hsit != NULL; hsit = hsit->next) {
181         comps_set_add(set, hsit->data);
182 
183     }
184     pairs2 = comps_objdict_pairs(c2->properties);
185     for (hsit = pairs2->first; hsit != NULL; hsit = hsit->next) {
186         if (comps_set_in(set, hsit->data)) {
187             comps_objdict_set(res->properties, ((COMPS_RTreePair*)hsit->data)->key,
188                   ((COMPS_RTreePair*)hsit->data)->data);
189         }
190     }
191     comps_hslist_destroy(&pairs1);
192     comps_hslist_destroy(&pairs2);
193     comps_set_clear(set);
194 
195     comps_set_init(set, NULL, NULL, NULL, &__comps_docgroupid_cmp_set);
196 
197     for (it = c1->group_ids->first; it != NULL; it = it->next) {
198         comps_set_add(set, it->comps_obj);
199     }
200     for (it = c2->group_ids->first; it != NULL; it = it->next) {
201         if (comps_set_in(set, it->comps_obj)) {
202             comps_doccategory_add_groupid(res,
203                         (COMPS_DocGroupId*)comps_object_copy(it->comps_obj));
204         }
205     }
206     comps_set_destroy(&set);
207     return res;
208 }
209 
comps_doccategory_xml(COMPS_DocCategory * category,xmlTextWriterPtr writer,COMPS_Log * log,COMPS_XMLOptions * xml_options,COMPS_DefaultsOptions * def_options)210 signed char comps_doccategory_xml(COMPS_DocCategory *category,
211                                   xmlTextWriterPtr writer, COMPS_Log *log,
212                                   COMPS_XMLOptions *xml_options,
213                                   COMPS_DefaultsOptions *def_options) {
214     COMPS_ObjListIt *it;
215     COMPS_Object *obj;
216     COMPS_HSList *pairlist;
217     COMPS_HSListItem *hsit;
218 
219     static char* props[] = {"id", "name", "name", "desc", "desc", "display_order"};
220     static size_t type[] =   {0, 0, offsetof(COMPS_DocCategory, name_by_lang),
221                            0, offsetof(COMPS_DocCategory, desc_by_lang), 0};
222     static char* aliases[] = {NULL, NULL, NULL, "description", "description", NULL};
223     char *str;
224     int ret;
225 
226     if (category->group_ids->len == 0 && !xml_options->empty_categories) {
227         obj = comps_doccategory_get_id(category);
228         comps_log_error(log, COMPS_ERR_PKGLIST_EMPTY, 1, obj);
229         COMPS_OBJECT_DESTROY(obj);
230         return 1;
231     }
232     ret = xmlTextWriterStartElement(writer, BAD_CAST "category");
233     COMPS_XMLRET_CHECK()
234     if (xml_options->arch_output) {
235         obj = (COMPS_Object*)comps_doccategory_arches(category);
236         ret = __comps_xml_arch(obj, writer);
237         COMPS_OBJECT_DESTROY(obj);
238         COMPS_XMLRET_CHECK()
239     }
240     for (int i=0; i<6; i++) {
241         if (!type[i]) {
242             obj = comps_objdict_get_x(category->properties, props[i]);
243             if (obj) {
244                 str = comps_object_tostr(obj);
245                 __comps_xml_prop((aliases[i])?aliases[i]:props[i], str, writer);
246                 free(str);
247             } else {
248                 //printf("missing %s\n", props[i]);
249             }
250         } else {
251             pairlist = comps_objdict_pairs(*(COMPS_ObjDict**)
252                                            (((char*)category)+type[i]));
253             for (hsit = pairlist->first; hsit != NULL; hsit = hsit->next) {
254                 ret = xmlTextWriterStartElement(writer,
255                             (const xmlChar*)(aliases[i]?aliases[i]:props[i]));
256                 if (__comps_check_xml_get(ret, (COMPS_Object*)log) < 0) {
257                     comps_hslist_destroy(&pairlist);
258                     return -1;
259                 }
260                 ret = xmlTextWriterWriteAttribute(writer, (xmlChar*) "xml:lang",
261                         (xmlChar*) ((COMPS_ObjRTreePair*)hsit->data)->key);
262                 if (__comps_check_xml_get(ret, (COMPS_Object*)log) < 0) {
263                     comps_hslist_destroy(&pairlist);
264                     return -1;
265                 }
266                 str = comps_object_tostr(((COMPS_ObjRTreePair*)hsit->data)->data);
267                 ret = xmlTextWriterWriteString(writer, (xmlChar*)str);
268                 free(str);
269                 if (__comps_check_xml_get(ret, (COMPS_Object*)log) < 0) {
270                     comps_hslist_destroy(&pairlist);
271                     return -1;
272                 }
273                 ret = xmlTextWriterEndElement(writer);
274                 if (__comps_check_xml_get(ret, (COMPS_Object*)log) < 0) {
275                     comps_hslist_destroy(&pairlist);
276                     return -1;
277                 }
278             }
279             comps_hslist_destroy(&pairlist);
280         }
281     }
282     if (category->group_ids->len || xml_options->empty_grouplist) {
283         ret = xmlTextWriterStartElement(writer, (xmlChar*)"grouplist");
284         COMPS_XMLRET_CHECK()
285         for (it = category->group_ids->first; it != NULL; it = it->next) {
286             comps_docgroupid_xml((COMPS_DocGroupId*)(COMPS_DocGroupId*)it->comps_obj,
287                                  writer, log, xml_options, def_options);
288         }
289         ret = xmlTextWriterEndElement(writer);
290         COMPS_XMLRET_CHECK()
291     }
292     ret = xmlTextWriterEndElement(writer);
293     COMPS_XMLRET_CHECK()
294     return 0;
295 }
296 
comps_doccategory_tostr_u(COMPS_Object * cat)297 char* comps_doccategory_tostr_u(COMPS_Object* cat) {
298     #define _cat_ ((COMPS_DocCategory*)cat)
299     char *ret, *name_by_lang_str, *desc_by_lang_str, *group_ids_str;
300     int total_len = 0;
301     const char *head = "<COMPS_Category ";
302     COMPS_Object *tmpprop;
303     COMPS_Object*(*getters[])(COMPS_DocCategory*)= {comps_doccategory_get_id,
304                                      comps_doccategory_get_name,
305                                      comps_doccategory_get_desc,
306                                      comps_doccategory_get_display_order};
307     char *props[4];
308     for (int i=0; i<4; i++) {
309         tmpprop = getters[i](_cat_);
310         props[i] = comps_object_tostr(tmpprop);
311         total_len += strlen(props[i]);
312         COMPS_OBJECT_DESTROY(tmpprop);
313     }
314     name_by_lang_str = comps_object_tostr((COMPS_Object*)_cat_->name_by_lang);
315     total_len += strlen(name_by_lang_str);
316     desc_by_lang_str = comps_object_tostr((COMPS_Object*)_cat_->desc_by_lang);
317     total_len += strlen(desc_by_lang_str);
318     group_ids_str = comps_object_tostr((COMPS_Object*)_cat_->group_ids);
319     total_len += strlen(group_ids_str);
320 
321     ret = malloc(sizeof(char) * (total_len+2+(6*2)+strlen(head)));
322     ret[0] = 0;
323     strcat(ret, head);
324     for (int i=0; i<4; i++) {
325         strcat(ret, props[i]);
326         free(props[i]);
327         strcat(ret, ", ");
328     }
329     strcat(ret, name_by_lang_str);
330     free(name_by_lang_str);
331     strcat(ret, ", ");
332     strcat(ret, desc_by_lang_str);
333     free(desc_by_lang_str);
334     strcat(ret, ", ");
335     strcat(ret, group_ids_str);
336     free(group_ids_str);
337     strcat(ret, ">");
338     return ret;
339     #undef _cat_
340 }
341 
comps_doccategory_arch_filter(COMPS_DocCategory * source,COMPS_ObjList * arches)342 COMPS_DocCategory* comps_doccategory_arch_filter(COMPS_DocCategory *source,
343                                                  COMPS_ObjList *arches) {
344     COMPS_ObjList *arches2;
345     COMPS_DocCategory *ret = COMPS_OBJECT_CREATE(COMPS_DocCategory, NULL);
346     COMPS_OBJECT_DESTROY(ret->properties);
347     ret->properties = (COMPS_ObjDict*)COMPS_OBJECT_COPY(source->properties);
348     COMPS_OBJECT_DESTROY(ret->name_by_lang);
349     ret->name_by_lang = (COMPS_ObjDict*)COMPS_OBJECT_COPY(source->name_by_lang);
350     COMPS_OBJECT_DESTROY(ret->desc_by_lang);
351     ret->desc_by_lang = (COMPS_ObjDict*)COMPS_OBJECT_COPY(source->desc_by_lang);
352     for (COMPS_ObjListIt *it = source->group_ids->first;
353          it != NULL; it = it->next) {
354         arches2 = comps_docgroupid_arches((COMPS_DocGroupId*)it->comps_obj);
355         if ((!arches2) || (__comps_objlist_intersected(arches, arches2))) {
356             comps_doccategory_add_groupid(ret, (COMPS_DocGroupId*)
357                                           comps_object_copy(it->comps_obj));
358         }
359         COMPS_OBJECT_DESTROY(arches2);
360     }
361     return ret;
362 }
363 
364 COMPS_ObjectInfo COMPS_DocCategory_ObjInfo = {
365     .obj_size = sizeof(COMPS_DocCategory),
366     .constructor = &comps_doccategory_create_u,
367     .destructor = &comps_doccategory_destroy_u,
368     .copy = &comps_doccategory_copy_u,
369     .obj_cmp = &comps_doccategory_cmp_u,
370     .to_str = &comps_doccategory_tostr_u
371 };
372 
373 COMPS_ValRuleGeneric* COMPS_DocCategory_ValidateRules[] = {
374     (COMPS_ValRuleGeneric*)&(COMPS_ValRuleProp){COMPS_VAL_RULE_PROP,
375                          .verbose_msg = "Category id check: ",
376                          .get_f = (COMPS_VAL_GETF) &comps_doccategory_get_id,
377                          .check_f = &comps_empty_check},
378     (COMPS_ValRuleGeneric*)&(COMPS_ValRuleList){COMPS_VAL_RULE_LIST,
379                          .verbose_msg = "Category unique package list check: ",
380                          .offset = offsetof(COMPS_DocCategory, group_ids),
381                          .check_f = &comps_objlist_unique_check},
382     NULL
383 };
384