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