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_doc.h"
21 #include "comps_set.h"
22 //#include "comps_types.h"
23 #include "comps_utils.h"
24 #include "comps_default.h"
25 
26 #include <stdio.h>
27 #include <assert.h>
28 static signed char comps_doc_xml(COMPS_Doc *doc, xmlTextWriterPtr writer,
29                                  COMPS_XMLOptions *xml_options,
30                                  COMPS_DefaultsOptions *def_options);
31 
comps_doc_create(COMPS_Doc * doc,COMPS_Object ** args)32 void comps_doc_create(COMPS_Doc* doc, COMPS_Object **args) {
33     doc->objects = COMPS_OBJECT_CREATE(COMPS_ObjDict, NULL);
34     doc->log = COMPS_OBJECT_CREATE(COMPS_Log, NULL);
35     //doc->log = comps_log_create(0);
36     if (args && args[0]->obj_info == &COMPS_Str_ObjInfo) {
37         doc->encoding = (COMPS_Str*) comps_object_incref(args[0]);
38     } else {
39         doc->encoding = NULL;
40     }
41     doc->doctype_name = comps_str(comps_default_doctype_name);
42     doc->doctype_sysid = comps_str(comps_default_doctype_sysid);
43     doc->doctype_pubid = comps_str(comps_default_doctype_pubid);
44     doc->lang = NULL;
45 }
COMPS_CREATE_u(doc,COMPS_Doc)46 COMPS_CREATE_u(doc, COMPS_Doc)
47 
48 void comps_doc_copy(COMPS_Doc *doc_dst, COMPS_Doc *doc_src) {
49     doc_dst->encoding = (COMPS_Str*) COMPS_OBJECT_COPY(doc_src->encoding);
50     doc_dst->doctype_name = (COMPS_Str*) COMPS_OBJECT_COPY(doc_src->doctype_name);
51     doc_dst->doctype_sysid = (COMPS_Str*) COMPS_OBJECT_COPY(doc_src->doctype_sysid);
52     doc_dst->doctype_pubid = (COMPS_Str*) COMPS_OBJECT_COPY(doc_src->doctype_pubid);
53     doc_dst->objects = (COMPS_ObjDict*) COMPS_OBJECT_COPY(doc_src->objects);
54 }
COMPS_COPY_u(doc,COMPS_Doc)55 COMPS_COPY_u(doc, COMPS_Doc)
56 
57 void comps_doc_destroy(COMPS_Doc *doc) {
58     if (doc != NULL) {
59         COMPS_OBJECT_DESTROY(doc->log);
60         COMPS_OBJECT_DESTROY(doc->objects);
61         COMPS_OBJECT_DESTROY(doc->encoding);
62         COMPS_OBJECT_DESTROY(doc->doctype_name);
63         COMPS_OBJECT_DESTROY(doc->doctype_sysid);
64         COMPS_OBJECT_DESTROY(doc->doctype_pubid);
65     }
66 }
COMPS_DESTROY_u(doc,COMPS_Doc)67 COMPS_DESTROY_u(doc, COMPS_Doc)
68 
69 signed char comps_doc_cmp_u(COMPS_Object *obj1, COMPS_Object *obj2) {
70     COMPS_Object *tmp1, *tmp2;
71     signed char ret;
72 
73     #define _doc1_ ((COMPS_Doc*)obj1)
74     #define _doc2_ ((COMPS_Doc*)obj2)
75 
76     if (!COMPS_OBJECT_CMP(_doc1_->encoding, _doc2_->encoding)) {
77         return 0;
78     }
79     if (!COMPS_OBJECT_CMP(_doc1_->doctype_name, _doc2_->doctype_name)) {
80         return 0;
81     }
82     if (!COMPS_OBJECT_CMP(_doc1_->doctype_sysid, _doc2_->doctype_sysid)) {
83         return 0;
84     }
85     if (!COMPS_OBJECT_CMP(_doc1_->doctype_pubid, _doc2_->doctype_pubid)) {
86         return 0;
87     }
88     tmp1 = (COMPS_Object*) comps_doc_categories(_doc1_);
89     tmp2 = (COMPS_Object*) comps_doc_categories(_doc2_);
90     ret = comps_object_cmp(tmp1, tmp2);
91     COMPS_OBJECT_DESTROY(tmp1);
92     COMPS_OBJECT_DESTROY(tmp2);
93     if (!ret) {
94         //printf("categories cmp fail\n");
95         return ret;
96     }
97 
98     tmp1 = (COMPS_Object*) comps_doc_groups(_doc1_);
99     tmp2 = (COMPS_Object*) comps_doc_groups(_doc2_);
100     ret = comps_object_cmp(tmp1, tmp2);
101     COMPS_OBJECT_DESTROY(tmp1);
102     COMPS_OBJECT_DESTROY(tmp2);
103     if (!ret) {
104         //printf("groups cmp fail\n");
105         return ret;
106     }
107 
108     tmp1 = (COMPS_Object*) comps_doc_environments(_doc1_);
109     tmp2 = (COMPS_Object*) comps_doc_environments(_doc2_);
110     ret = comps_object_cmp(tmp1, tmp2);
111     COMPS_OBJECT_DESTROY(tmp1);
112     COMPS_OBJECT_DESTROY(tmp2);
113     if (!ret) {
114         return ret;
115     }
116 
117     tmp1 = (COMPS_Object*) comps_doc_langpacks(_doc1_);
118     tmp2 = (COMPS_Object*) comps_doc_langpacks(_doc2_);
119     ret = comps_object_cmp(tmp1, tmp2);
120     COMPS_OBJECT_DESTROY(tmp1);
121     COMPS_OBJECT_DESTROY(tmp2);
122     if (!ret) {
123         return ret;
124     }
125 
126     tmp1 = (COMPS_Object*) comps_doc_blacklist(_doc1_);
127     tmp2 = (COMPS_Object*) comps_doc_blacklist(_doc2_);
128     ret = comps_object_cmp(tmp1, tmp2);
129     COMPS_OBJECT_DESTROY(tmp1);
130     COMPS_OBJECT_DESTROY(tmp2);
131     if (!ret) {
132         //printf("blacklist cmp fail\n");
133         return ret;
134     }
135 
136     tmp1 = (COMPS_Object*) comps_doc_whiteout(_doc1_);
137     tmp2 = (COMPS_Object*) comps_doc_whiteout(_doc2_);
138     ret = comps_object_cmp(tmp1, tmp2);
139     COMPS_OBJECT_DESTROY(tmp1);
140     COMPS_OBJECT_DESTROY(tmp2);
141     if (!ret) {
142         //printf("whiteout cmp fail\n");
143         return ret;
144     }
145 
146     return ret;
147 }
148 
comps_doc_clear(COMPS_Doc * doc)149 inline void comps_doc_clear(COMPS_Doc *doc) {
150     if (doc == NULL) return;
151     //comps_objdict_clear(doc->objects);
152 }
153 
154 COMPS_DOC_GETOBJLIST(groups)        /*comps_doc.h macro*/
COMPS_DOC_SETOBJLIST(groups)155 COMPS_DOC_SETOBJLIST(groups) /*comps_doc.h macro*/
156 COMPS_DOC_ADDOBJLIST(groups, group, COMPS_DocGroup) /*comps_doc.h macro*/
157 COMPS_DOC_GETOBJLIST(categories)    /*comps_doc.h macro*/
158 COMPS_DOC_SETOBJLIST(categories) /*comps_doc.h macro*/
159 COMPS_DOC_ADDOBJLIST(categories, category, COMPS_DocCategory) /*comps_doc.h macro*/
160 COMPS_DOC_GETOBJLIST(environments)  /*comps_doc.h macro*/
161 COMPS_DOC_SETOBJLIST(environments) /*comps_doc.h macro*/
162 COMPS_DOC_ADDOBJLIST(environments, environment, COMPS_DocEnv) /*comps_doc.h macro*/
163 COMPS_DOC_GETOBJDICT(langpacks)     /*comps_doc.h macro*/
164 COMPS_DOC_SETOBJDICT(langpacks) /*comps_doc.h macro*/
165 COMPS_DOC_ADDOBJDICT(langpacks, langpack) /*comps_doc.h macro*/
166 COMPS_DOC_GETOBJMDICT(blacklist)     /*comps_doc.h macro*/
167 COMPS_DOC_SETOBJMDICT(blacklist) /*comps_doc.h macro*/
168 COMPS_DOC_ADDOBJMDICT(blacklist,  blacklist) /*comps_doc.h macro*/
169 COMPS_DOC_GETOBJMDICT(whiteout)      /*comps_doc.h macro*/
170 COMPS_DOC_SETOBJMDICT(whiteout) /*comps_doc.h macro*/
171 COMPS_DOC_ADDOBJMDICT(whiteout,  whiteout) /*comps_doc.h macro*/
172 
173 COMPS_DOC_SETPROP(lang,  COMPS_Str) /*comps_doc.h macro*/
174 
175 
176 signed char comps2xml_f(COMPS_Doc * doc, char *filename, char stdoutredirect,
177                         COMPS_XMLOptions *xml_options,
178                         COMPS_DefaultsOptions *def_options) {
179     xmlDocPtr xmldoc;
180     int retc;
181     char *str;
182     signed char genret;
183 
184     doc->log->std_out = stdoutredirect;
185     xmlTextWriterPtr writer = xmlNewTextWriterDoc(&xmldoc, 0);
186 
187     if ((COMPS_Object*)doc->encoding) {
188         str = comps_object_tostr((COMPS_Object*)doc->encoding);
189         retc = xmlTextWriterStartDocument(writer, NULL, str, NULL);
190         free(str);
191     } else {
192         retc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
193     }
194     if (retc<0)
195         comps_log_error(doc->log, COMPS_ERR_XMLGEN, 0);
196 
197     if (!xml_options)
198         xml_options = &COMPS_XMLDefaultOptions;
199     if (!def_options)
200         def_options = &COMPS_DDefaultsOptions;
201     genret = comps_doc_xml(doc, writer, xml_options, def_options);
202     retc = xmlTextWriterEndDocument(writer);
203     if (retc<0)
204         comps_log_error(doc->log, COMPS_ERR_XMLGEN, 0);
205 
206     retc = xmlSaveFormatFileEnc(filename, xmldoc, NULL, 1);
207     if (retc<0)
208         comps_log_error_x(doc->log, COMPS_ERR_WRITEF,
209                           1, comps_str(filename));
210 
211     xmlFreeTextWriter(writer);
212     xmlFreeDoc(xmldoc);
213     xmlCleanupParser();
214     xmlMemoryDump();
215     return genret;
216 }
217 
comps2xml_str(COMPS_Doc * doc,COMPS_XMLOptions * xml_options,COMPS_DefaultsOptions * def_options)218 char* comps2xml_str(COMPS_Doc *doc, COMPS_XMLOptions *xml_options,
219                     COMPS_DefaultsOptions *def_options) {
220     xmlDocPtr xmldoc;
221     const char *xmlstr;
222     signed char genret;
223     char *str, *ret;
224     int retc;
225 
226     xmlBuffer *xmlbuff = xmlBufferCreate();
227     xmlOutputBuffer *xmlobuff = xmlOutputBufferCreateBuffer(xmlbuff, 0);
228     xmlTextWriterPtr writer = xmlNewTextWriterDoc(&xmldoc, 0);
229 
230     if ((COMPS_Object*)doc->encoding) {
231         str = comps_object_tostr((COMPS_Object*)doc->encoding);
232         retc = xmlTextWriterStartDocument(writer, NULL, str, NULL);
233         free(str);
234     } else {
235         retc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
236     }
237     if (retc<0) comps_log_error(doc->log, COMPS_ERR_XMLGEN, 0);
238 
239     if (!xml_options)
240         xml_options = &COMPS_XMLDefaultOptions;
241     if (!def_options)
242         def_options = &COMPS_DDefaultsOptions;
243     genret = comps_doc_xml(doc, writer, xml_options, def_options);
244     if (genret)
245         comps_log_error(doc->log, COMPS_ERR_XMLGEN, 0);
246     if (retc<0)
247         comps_log_error(doc->log, COMPS_ERR_XMLGEN, 0);
248     retc = xmlTextWriterEndDocument(writer);
249     if (retc<0) comps_log_error(doc->log, COMPS_ERR_XMLGEN, 0);
250     xmlSaveFormatFileTo(xmlobuff, xmldoc, NULL, 1);
251 
252     xmlFreeTextWriter(writer);
253     xmlFreeDoc(xmldoc);
254 
255     xmlstr =(char*) xmlBufferContent(xmlbuff);
256     ret =  malloc(sizeof(char) * (strlen(xmlstr)+1));
257     if (ret == NULL) {
258         xmlBufferFree(xmlbuff);
259         xmlCleanupParser();
260         xmlMemoryDump();
261         return NULL;
262     } else {
263         memcpy(ret, xmlstr, sizeof(char)*(strlen(xmlstr)+1));
264     }
265     xmlBufferFree(xmlbuff);
266 
267     xmlCleanupParser();
268     xmlMemoryDump();
269     return ret;
270 }
271 
comps_doc_union(COMPS_Doc * c1,COMPS_Doc * c2)272 COMPS_Doc* comps_doc_union(COMPS_Doc *c1, COMPS_Doc *c2) {
273     COMPS_ObjListIt *it;
274     COMPS_Set *set;
275     COMPS_Doc *res;
276     COMPS_DocGroup *tmpgroup;
277     COMPS_DocCategory *tmpcat;
278     COMPS_DocEnv *tmpenv;
279     COMPS_HSListItem *hsit;
280     COMPS_ObjList *groups = comps_doc_groups(c1);
281     COMPS_ObjList *categories = comps_doc_categories(c1);
282     COMPS_ObjList *envs = comps_doc_environments(c1);
283     COMPS_ObjDict *langpacks, *d1, *d2;
284 
285     void *tmpdata;
286     res = COMPS_OBJECT_CREATE(COMPS_Doc, (COMPS_Object*[]){(COMPS_Object*)
287                                                            c1->encoding});
288 
289     set = comps_set_create();
290     comps_set_init(set, NULL, NULL, NULL, &__comps_docgroup_idcmp);
291 
292     for (it = groups ? groups->first : NULL; it != NULL; it = it->next) {
293         comps_set_add(set, comps_object_copy(it->comps_obj));
294     }
295     COMPS_OBJECT_DESTROY(groups);
296     groups = comps_doc_groups(c2);
297     for (it = groups ? groups->first : NULL; it != NULL; it = it->next) {
298         if (comps_set_in(set, it->comps_obj)) {
299             tmpgroup = comps_docgroup_union(
300                                 (COMPS_DocGroup*)comps_set_data_at(set,
301                                                                it->comps_obj),
302                                 (COMPS_DocGroup*)it->comps_obj);
303             tmpdata = comps_set_data_at(set, it->comps_obj);
304             comps_set_remove(set, it->comps_obj);
305             COMPS_OBJECT_DESTROY(tmpdata);
306             comps_set_add(set, tmpgroup);
307         } else {
308             comps_set_add(set, comps_object_copy(it->comps_obj));
309         }
310     }
311     COMPS_OBJECT_DESTROY(groups);
312     for (hsit = set->data->first; hsit != NULL; hsit = hsit->next) {
313         comps_doc_add_group(res, hsit->data);
314     }
315     comps_set_clear(set);
316 
317     comps_set_init(set, NULL, NULL, NULL, &__comps_doccategory_idcmp);
318     for (it = categories ? categories->first : NULL; it != NULL; it = it->next) {
319         comps_set_add(set, comps_object_copy(it->comps_obj));
320     }
321     COMPS_OBJECT_DESTROY(categories);
322     categories = comps_doc_categories(c2);
323     for (it = categories ? categories->first : NULL; it != NULL; it = it->next) {
324         if (comps_set_in(set, it->comps_obj)) {
325             tmpcat = comps_doccategory_union(
326                                 (COMPS_DocCategory*)comps_set_data_at(set,
327                                                                 it->comps_obj),
328                                 (COMPS_DocCategory*)it->comps_obj);
329             tmpdata = comps_set_data_at(set, it->comps_obj);
330             comps_set_remove(set, it->comps_obj);
331             COMPS_OBJECT_DESTROY(tmpdata);
332             comps_set_add(set, tmpcat);
333         } else {
334             comps_set_add(set, comps_object_copy(it->comps_obj));
335         }
336     }
337     COMPS_OBJECT_DESTROY(categories);
338     for (hsit = set->data->first; hsit != NULL; hsit = hsit->next) {
339         comps_doc_add_category(res, hsit->data);
340     }
341     comps_set_clear(set);
342 
343     comps_set_init(set, NULL, NULL, NULL, &__comps_docenv_idcmp);
344     if (envs) {
345         for (it = envs->first; it != NULL; it = it->next) {
346             comps_set_add(set, comps_object_copy(it->comps_obj));
347         }
348     }
349     COMPS_OBJECT_DESTROY(envs);
350     envs = comps_doc_environments(c2);
351     if (envs) {
352         for (it = envs->first; it != NULL; it = it->next) {
353             if (comps_set_in(set, it->comps_obj)) {
354                 tmpenv = comps_docenv_union(
355                                     (COMPS_DocEnv*)comps_set_data_at(set,
356                                                               it->comps_obj),
357                                     (COMPS_DocEnv*)it->comps_obj);
358                 tmpdata = comps_set_data_at(set, it->comps_obj);
359                 comps_set_remove(set, it->comps_obj);
360                 comps_object_destroy((COMPS_Object*)tmpdata);
361                 comps_set_add(set, tmpenv);
362             } else {
363                 comps_set_add(set, comps_object_copy(it->comps_obj));
364             }
365         }
366     }
367     COMPS_OBJECT_DESTROY(envs);
368     for (hsit = set->data->first; hsit != NULL; hsit = hsit->next) {
369         comps_doc_add_environment(res, hsit->data);
370     }
371     comps_set_destroy(&set);
372 
373     d1 = comps_doc_langpacks(c1);
374     d2 = comps_doc_langpacks(c2);
375     langpacks = comps_objdict_union(d1,d2);
376     COMPS_OBJECT_DESTROY(d1);
377     COMPS_OBJECT_DESTROY(d2);
378     comps_doc_set_langpacks(res, langpacks);
379     COMPS_OBJECT_DESTROY(langpacks);
380     return res;
381 }
382 
383 /**
384  * Make intersection of two existing COMPS_Doc objects. Result intersection is
385  * completly new COMPS_Doc object (deep copy of those two).
386  * Intersection is made by objects ids. Objects of intersection is created
387  * by intersecting specific objects.
388  * @see comps_docgroup_intersect
389  * @see comps_doccategory_intersect
390  * @see comps_docenv_intersect
391  * @param c1 COMPS_Doc object
392  * @param c2 COMPS_Doc object
393  * @return new COMPS_Doc object
394  */
comps_doc_intersect(COMPS_Doc * c1,COMPS_Doc * c2)395 COMPS_Doc* comps_doc_intersect(COMPS_Doc *c1, COMPS_Doc *c2) {
396     COMPS_ObjListIt *it;
397     COMPS_Set *set;
398     COMPS_Doc *res;
399     COMPS_DocGroup *tmpgroup;
400     COMPS_DocCategory *tmpcat;
401     COMPS_DocEnv *tmpenv;
402     COMPS_ObjList *groups = comps_doc_groups(c1);
403     COMPS_ObjList *categories = comps_doc_categories(c1);
404     COMPS_ObjList *envs = comps_doc_environments(c1);
405 
406     res = COMPS_OBJECT_CREATE(COMPS_Doc, (COMPS_Object*[])
407                                          {(COMPS_Object*)c1->encoding});
408 
409     set = comps_set_create();
410     comps_set_init(set, NULL, NULL, NULL, &__comps_docgroup_idcmp);
411 
412     for (it = groups->first; it != NULL; it = it->next) {
413         comps_set_add(set, it->comps_obj);
414     }
415     COMPS_OBJECT_DESTROY(groups);
416     groups = comps_doc_groups(c2);
417     for (it = groups->first; it != NULL; it = it->next) {
418         if (comps_set_in(set, it->comps_obj)) {
419             tmpgroup = comps_docgroup_intersect(
420                                 (COMPS_DocGroup*)it->comps_obj,
421                                 (COMPS_DocGroup*)comps_set_data_at(set,
422                                                                    it->comps_obj));
423             comps_doc_add_group(res, tmpgroup);
424         }
425     }
426     comps_set_clear(set);
427 
428     comps_set_init(set, NULL, NULL, NULL, &__comps_doccategory_idcmp);
429     for (it = categories->first; it != NULL; it = it->next) {
430         comps_set_add(set, it->comps_obj);
431     }
432     COMPS_OBJECT_DESTROY(categories);
433     categories = comps_doc_categories(c2);
434     for (it = categories->first; it != NULL; it = it->next) {
435         if (comps_set_in(set, it->comps_obj)) {
436             tmpcat = comps_doccategory_intersect(
437                                 (COMPS_DocCategory*)it->comps_obj,
438                                 (COMPS_DocCategory*)comps_set_data_at(set,
439                                                                     it->comps_obj));
440             comps_doc_add_category(res, tmpcat);
441         }
442     }
443     comps_set_clear(set);
444 
445     comps_set_init(set, NULL, NULL, NULL, &__comps_docenv_idcmp);
446     for (it = envs->first; it != NULL; it = it->next) {
447         comps_set_add(set, it->comps_obj);
448     }
449     COMPS_OBJECT_DESTROY(envs);
450     envs = comps_doc_environments(c2);
451     for (it = envs->first; it != NULL; it = it->next) {
452         if (comps_set_in(set, it->comps_obj)) {
453             tmpenv = comps_docenv_intersect(
454                                 (COMPS_DocEnv*)it->comps_obj,
455                                 (COMPS_DocEnv*)comps_set_data_at(set,it->comps_obj));
456             comps_doc_add_environment(res, tmpenv);
457         }
458     }
459     comps_set_destroy(&set);
460     COMPS_OBJECT_DESTROY(groups);
461     COMPS_OBJECT_DESTROY(categories);
462     COMPS_OBJECT_DESTROY(envs);
463 
464     return res;
465 }
466 
comps_doc_get_groups(COMPS_Doc * doc,char * id,char * name,char * desc,char * lang,int flags)467 COMPS_ObjList* comps_doc_get_groups(COMPS_Doc *doc, char *id, char *name,
468                                     char *desc, char *lang, int flags) {
469     COMPS_ObjListIt *it;
470     COMPS_ObjList *ret;
471     unsigned int matched, matched_max;
472     matched_max = 0;
473     COMPS_ObjList *groups = comps_doc_groups(doc);
474     COMPS_Str *objid, *objname, *objdesc, *tmp_prop;
475     objid = comps_str(id);
476     objname = comps_str(name);
477     objdesc = comps_str(desc);
478 
479     ret = COMPS_OBJECT_CREATE(COMPS_ObjList, NULL);
480     #define group ((COMPS_DocGroup*)it->comps_obj)
481 
482     if (id != NULL) matched_max++;
483     if (name != NULL) matched_max++;
484     if (desc != NULL) matched_max++;
485 
486     for (it = (groups)?groups->first:NULL; it != NULL; it = it->next) {
487         matched = 0;
488         tmp_prop = (COMPS_Str*)comps_docgroup_get_id(group);
489         if (id && tmp_prop && comps_str_fnmatch(tmp_prop, id, flags)) {
490             matched++;
491         }
492         COMPS_OBJECT_DESTROY(tmp_prop);
493         tmp_prop = (COMPS_Str*)comps_docgroup_get_name(group);
494         if (name && !lang && tmp_prop && comps_str_fnmatch(tmp_prop, name, flags))
495             matched++;
496         else if (name && lang != NULL) {
497             COMPS_OBJECT_DESTROY(tmp_prop);
498             tmp_prop = (COMPS_Str*)comps_objdict_get(group->name_by_lang, lang);
499             //printf("tmp_prop %s\n", tmp_prop->val);
500             if (tmp_prop && comps_str_fnmatch(tmp_prop, name, flags)) matched++;
501         }
502         COMPS_OBJECT_DESTROY(tmp_prop);
503         tmp_prop = (COMPS_Str*)comps_docgroup_get_desc(group);
504         if (desc && tmp_prop && comps_str_fnmatch(tmp_prop, desc, flags) == 1)
505             matched++;
506         else if (desc && lang != NULL) {
507             COMPS_OBJECT_DESTROY(tmp_prop);
508             tmp_prop = (COMPS_Str*)comps_objdict_get(group->desc_by_lang, lang);
509             if (tmp_prop && comps_str_fnmatch(tmp_prop, desc, flags)) matched++;
510         }
511         if (matched == matched_max) {
512             comps_objlist_append(ret, (COMPS_Object*)group);
513         }
514         COMPS_OBJECT_DESTROY(tmp_prop);
515     }
516     COMPS_OBJECT_DESTROY(objid);
517     COMPS_OBJECT_DESTROY(objname);
518     COMPS_OBJECT_DESTROY(objdesc);
519     COMPS_OBJECT_DESTROY(groups);
520     return ret;
521     #undef group
522 }
523 
comps_doc_get_categories(COMPS_Doc * doc,char * id,char * name,char * desc,char * lang,int flags)524 COMPS_ObjList* comps_doc_get_categories(COMPS_Doc *doc, char *id, char *name,
525                                         char *desc, char *lang, int flags) {
526     COMPS_ObjListIt *it;
527     COMPS_ObjList *ret;
528     unsigned int matched, matched_max;
529     matched_max = 0;
530     COMPS_ObjList *categories = comps_doc_categories(doc);
531     //COMPS_Object *tmp_prop;
532     COMPS_Str *objid, *objname, *objdesc, *tmp_prop;
533     objid = comps_str(id);
534     objname = comps_str(name);
535     objdesc = comps_str(desc);
536 
537     ret = COMPS_OBJECT_CREATE(COMPS_ObjList, NULL);
538     #define category ((COMPS_DocCategory*)it->comps_obj)
539 
540     if (id != NULL) matched_max++;
541     if (name != NULL) matched_max++;
542     if (desc != NULL) matched_max++;
543 
544     for (it = (categories)?categories->first:NULL; it != NULL; it = it->next) {
545         matched = 0;
546         tmp_prop = (COMPS_Str*)comps_doccategory_get_id(category);
547         if (id && tmp_prop && comps_str_fnmatch(tmp_prop, id, flags)) {
548             matched++;
549         }
550         COMPS_OBJECT_DESTROY(tmp_prop);
551         tmp_prop = (COMPS_Str*)comps_doccategory_get_name(category);
552         if (name && !lang && tmp_prop && comps_str_fnmatch(tmp_prop, name, flags))
553             matched++;
554         else if (name && lang != NULL) {
555             COMPS_OBJECT_DESTROY(tmp_prop);
556             tmp_prop = (COMPS_Str*)comps_objdict_get(category->name_by_lang, lang);
557             if (tmp_prop && comps_str_fnmatch(tmp_prop, name, flags)) matched++;
558         }
559         COMPS_OBJECT_DESTROY(tmp_prop);
560         tmp_prop = (COMPS_Str*)comps_doccategory_get_desc(category);
561         if (desc && !lang && tmp_prop && comps_str_fnmatch(tmp_prop, desc, flags))
562             matched++;
563         else if (desc && lang != NULL) {
564             COMPS_OBJECT_DESTROY(tmp_prop);
565             tmp_prop = (COMPS_Str*)comps_objdict_get(category->desc_by_lang, lang);
566             if (tmp_prop && comps_str_fnmatch(tmp_prop, desc, flags)) matched++;
567         }
568         if (matched == matched_max) {
569             comps_objlist_append(ret, (COMPS_Object*)category);
570         }
571         COMPS_OBJECT_DESTROY(tmp_prop);
572     }
573     COMPS_OBJECT_DESTROY(objid);
574     COMPS_OBJECT_DESTROY(objname);
575     COMPS_OBJECT_DESTROY(objdesc);
576     COMPS_OBJECT_DESTROY(categories);
577     return ret;
578     #undef category
579 }
580 
comps_doc_get_envs(COMPS_Doc * doc,char * id,char * name,char * desc,char * lang,int flags)581 COMPS_ObjList* comps_doc_get_envs(COMPS_Doc *doc, char *id, char *name,
582                                   char *desc, char *lang, int flags) {
583     COMPS_ObjListIt *it;
584     COMPS_ObjList *ret;
585     unsigned int matched, matched_max;
586     matched_max = 0;
587     COMPS_ObjList *envs = comps_doc_environments(doc);
588     //COMPS_Object *tmp_prop;
589     COMPS_Str *objid, *objname, *objdesc, *tmp_prop;
590     objid = comps_str(id);
591     objname = comps_str(name);
592     objdesc = comps_str(desc);
593 
594     ret = COMPS_OBJECT_CREATE(COMPS_ObjList, NULL);
595     #define env ((COMPS_DocEnv*)it->comps_obj)
596 
597     if (id != NULL) matched_max++;
598     if (name != NULL) matched_max++;
599     if (desc != NULL) matched_max++;
600 
601     for (it = (envs)?envs->first:NULL; it != NULL; it = it->next) {
602         matched = 0;
603         tmp_prop = (COMPS_Str*)comps_docenv_get_id(env);
604         if (id && tmp_prop && comps_str_fnmatch(tmp_prop, id, flags)) {
605             matched++;
606         }
607         COMPS_OBJECT_DESTROY(tmp_prop);
608         tmp_prop = (COMPS_Str*)comps_docenv_get_name(env);
609         if (name && !lang && tmp_prop && comps_str_fnmatch(tmp_prop, name, flags))
610             matched++;
611         else if (name && lang != NULL) {
612             COMPS_OBJECT_DESTROY(tmp_prop);
613             tmp_prop = (COMPS_Str*)comps_objdict_get(env->name_by_lang, lang);
614             if (tmp_prop && comps_str_fnmatch(tmp_prop, name, flags)) matched++;
615         }
616         COMPS_OBJECT_DESTROY(tmp_prop);
617         tmp_prop = (COMPS_Str*)comps_docenv_get_desc(env);
618         if (desc && !lang && tmp_prop && comps_str_fnmatch(tmp_prop, desc, flags))
619             matched++;
620         else if (desc && lang != NULL) {
621             COMPS_OBJECT_DESTROY(tmp_prop);
622             tmp_prop = (COMPS_Str*)comps_objdict_get(env->desc_by_lang, lang);
623             if (tmp_prop && comps_str_fnmatch(tmp_prop, desc, flags)) matched++;
624         }
625         if (matched == matched_max) {
626             comps_objlist_append(ret, (COMPS_Object*)env);
627         }
628         COMPS_OBJECT_DESTROY(tmp_prop);
629     }
630     COMPS_OBJECT_DESTROY(objid);
631     COMPS_OBJECT_DESTROY(objname);
632     COMPS_OBJECT_DESTROY(objdesc);
633     COMPS_OBJECT_DESTROY(envs);
634     return ret;
635     #undef env
636 }
637 
comps_doc_xml(COMPS_Doc * doc,xmlTextWriterPtr writer,COMPS_XMLOptions * xml_options,COMPS_DefaultsOptions * def_options)638 static signed char comps_doc_xml(COMPS_Doc *doc, xmlTextWriterPtr writer,
639                                  COMPS_XMLOptions *xml_options,
640                                  COMPS_DefaultsOptions *def_options) {
641     COMPS_ObjListIt *it;
642     COMPS_ObjList *list;
643     COMPS_ObjDict *dict;
644     COMPS_ObjMDict *mdict;
645     COMPS_HSList *hslist;
646     COMPS_HSListItem *hsit;
647     char *tmp;
648     int retc;
649     signed char ret = 0, tmpret;
650 
651     retc = xmlTextWriterStartDTD(writer, (const xmlChar*)doc->doctype_name->val,
652                                   (const xmlChar*)doc->doctype_pubid->val,
653                                   (const xmlChar*)doc->doctype_sysid->val);
654     xmlTextWriterEndDTD(writer);
655     if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) return -1;
656 
657     retc = xmlTextWriterStartElement(writer, BAD_CAST "comps");
658     if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) return -1;
659     list = comps_doc_groups(doc);
660     if (list) {
661         for (it = list->first; it != NULL; it = it->next) {
662             tmpret = comps_docgroup_xml((COMPS_DocGroup*)it->comps_obj,
663                                         writer, doc->log, xml_options,
664                                         def_options);
665             if (tmpret == -1) return -1;
666             else ret += tmpret;
667         }
668     }
669     COMPS_OBJECT_DESTROY(list);
670     list = comps_doc_categories(doc);
671     if (list) {
672         for (it = list->first; it != NULL; it = it->next) {
673             tmpret = comps_doccategory_xml((COMPS_DocCategory*)it->comps_obj,
674                                            writer, doc->log, xml_options,
675                                            def_options);
676             if (tmpret == -1) return -1;
677             else ret += tmpret;
678         }
679     }
680     COMPS_OBJECT_DESTROY(list);
681     list = comps_doc_environments(doc);
682     if (list) {
683         for (it = list->first; it != NULL; it = it->next) {
684             tmpret = comps_docenv_xml((COMPS_DocEnv*)it->comps_obj,
685                                       writer, doc->log, xml_options,
686                                       def_options);
687             if (tmpret == -1) return -1;
688             else ret += tmpret;
689         }
690     }
691     COMPS_OBJECT_DESTROY(list);
692     dict = comps_doc_langpacks(doc);
693     if (dict && dict->len) {
694         retc = xmlTextWriterStartElement(writer, BAD_CAST "langpacks");
695         if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
696             COMPS_OBJECT_DESTROY(dict);
697             return -1;
698         }
699         hslist = comps_objrtree_pairs(dict);
700 
701         for (hsit = hslist->first; hsit != NULL; hsit = hsit->next) {
702             retc = xmlTextWriterStartElement(writer, BAD_CAST "match");
703             if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
704                 COMPS_OBJECT_DESTROY(dict);
705                 comps_hslist_destroy(&hslist);
706                 return -1;
707             }
708 
709             xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
710                     (xmlChar*) ((COMPS_ObjRTreePair*)hsit->data)->key);
711 
712             tmp = comps_object_tostr(((COMPS_ObjRTreePair*)hsit->data)->data);
713             xmlTextWriterWriteAttribute(writer, BAD_CAST "install", BAD_CAST tmp);
714             free(tmp);
715 
716             retc = xmlTextWriterEndElement(writer);
717             if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
718                 COMPS_OBJECT_DESTROY(dict);
719                 comps_hslist_destroy(&hslist);
720                 return -1;
721             }
722         }
723         comps_hslist_destroy(&hslist);
724 
725         retc = xmlTextWriterEndElement(writer);
726         if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
727             COMPS_OBJECT_DESTROY(dict);
728             return -1;
729         }
730     }
731     COMPS_OBJECT_DESTROY(dict);
732 
733     mdict = comps_doc_blacklist(doc);
734     if (mdict && mdict->len) {
735         retc = xmlTextWriterStartElement(writer, BAD_CAST "blacklist");
736         if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
737             return -1;
738         }
739         hslist = comps_objmrtree_pairs(mdict);
740 
741         for (hsit = hslist->first; hsit != NULL; hsit = hsit->next) {
742             for (it = ((COMPS_ObjMRTreePair*)hsit->data)->data->first;
743                  it != NULL; it = it->next) {
744                 retc = xmlTextWriterStartElement(writer, BAD_CAST "package");
745                 if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
746                     comps_hslist_destroy(&hslist);
747                     return -1;
748                 }
749                 xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
750                         (xmlChar*) ((COMPS_ObjRTreePair*)hsit->data)->key);
751 
752                 tmp = comps_object_tostr(it->comps_obj);
753                 xmlTextWriterWriteAttribute(writer, BAD_CAST "arch", BAD_CAST tmp);
754                 free(tmp);
755 
756                 retc = xmlTextWriterEndElement(writer);
757                 if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
758                     comps_hslist_destroy(&hslist);
759                     return -1;
760                 }
761             }
762         }
763         comps_hslist_destroy(&hslist);
764 
765         retc = xmlTextWriterEndElement(writer);
766         if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
767             return -1;
768         }
769     }
770     COMPS_OBJECT_DESTROY(mdict);
771     mdict = comps_doc_whiteout(doc);
772     if (mdict && mdict->len) {
773         retc = xmlTextWriterStartElement(writer, BAD_CAST "whiteout");
774         if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
775             COMPS_OBJECT_DESTROY(mdict);
776             return -1;
777         }
778         hslist = comps_objmrtree_pairs(mdict);
779 
780         for (hsit = hslist->first; hsit != NULL; hsit = hsit->next) {
781             for (it = ((COMPS_ObjMRTreePair*)hsit->data)->data->first;
782                  it != NULL; it = it->next) {
783                 retc = xmlTextWriterStartElement(writer, BAD_CAST "ignoredep");
784                 if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
785                     comps_hslist_destroy(&hslist);
786                     return -1;
787                 }
788 
789                 xmlTextWriterWriteAttribute(writer, BAD_CAST "requires",
790                         (xmlChar*) ((COMPS_ObjRTreePair*)hsit->data)->key);
791 
792                 tmp = comps_object_tostr(it->comps_obj);
793                 xmlTextWriterWriteAttribute(writer, BAD_CAST "package", BAD_CAST tmp);
794                 free(tmp);
795 
796                 retc = xmlTextWriterEndElement(writer);
797                 if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
798                     comps_hslist_destroy(&hslist);
799                     return -1;
800                 }
801             }
802         }
803         comps_hslist_destroy(&hslist);
804 
805         retc = xmlTextWriterEndElement(writer);
806         if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) {
807             return -1;
808         }
809     }
810     COMPS_OBJECT_DESTROY(mdict);
811     retc = xmlTextWriterEndElement(writer);
812     if (__comps_check_xml_get(retc, (COMPS_Object*)doc->log) < 0) return -1;
813     return ret;
814 }
815 
comps_doc_doctype_name_get(COMPS_Doc * doc)816 COMPS_Str* comps_doc_doctype_name_get(COMPS_Doc* doc) {
817     return (COMPS_Str*)COMPS_OBJECT_INCREF(doc->doctype_name);
818 }
comps_doc_doctype_pubid_get(COMPS_Doc * doc)819 COMPS_Str* comps_doc_doctype_pubid_get(COMPS_Doc* doc) {
820     return (COMPS_Str*)COMPS_OBJECT_INCREF(doc->doctype_pubid);
821 }
comps_doc_doctype_sysid_get(COMPS_Doc * doc)822 COMPS_Str* comps_doc_doctype_sysid_get(COMPS_Doc* doc) {
823     return (COMPS_Str*)COMPS_OBJECT_INCREF(doc->doctype_sysid);
824 }
comps_doc_doctype_name_set(COMPS_Doc * doc,COMPS_Str * val)825 void comps_doc_doctype_name_set(COMPS_Doc* doc, COMPS_Str *val) {
826     COMPS_OBJECT_REPLACE(doc->doctype_name, COMPS_Str, val);
827 }
comps_doc_doctype_sysid_set(COMPS_Doc * doc,COMPS_Str * val)828 void comps_doc_doctype_sysid_set(COMPS_Doc* doc, COMPS_Str *val) {
829     COMPS_OBJECT_REPLACE(doc->doctype_name, COMPS_Str, val);
830 }
comps_doc_doctype_pubid_set(COMPS_Doc * doc,COMPS_Str * val)831 void comps_doc_doctype_pubid_set(COMPS_Doc* doc, COMPS_Str *val) {
832     COMPS_OBJECT_REPLACE(doc->doctype_name, COMPS_Str, val);
833 }
834 
835 
comps_doc_arch_filter(COMPS_Doc * source,COMPS_ObjList * arches)836 COMPS_Doc* comps_doc_arch_filter(COMPS_Doc *source, COMPS_ObjList *arches) {
837     COMPS_ObjList *list, *arches2;
838     COMPS_Doc *ret;
839     COMPS_DocCategory *cat;
840     COMPS_DocGroup *group;
841     COMPS_DocEnv *env;
842 
843     ret = COMPS_OBJECT_CREATE(COMPS_Doc, (COMPS_Object*[])
844                                          {(COMPS_Object*)source->encoding});
845     list = comps_doc_categories(source);
846     for (COMPS_ObjListIt *it = list->first; it != NULL; it = it->next) {
847         arches2 = comps_doccategory_arches((COMPS_DocCategory*)it->comps_obj);
848         if ((!arches2) || (__comps_objlist_intersected(arches, arches2))) {
849             cat = comps_doccategory_arch_filter((COMPS_DocCategory*)it->comps_obj,
850                                                 arches);
851             comps_doc_add_category(ret, cat);
852         }
853         COMPS_OBJECT_DESTROY(arches2);
854     }
855     COMPS_OBJECT_DESTROY(list);
856     list = comps_doc_groups(source);
857     for (COMPS_ObjListIt *it = list->first; it != NULL; it = it->next) {
858         arches2 = comps_docgroup_arches((COMPS_DocGroup*)it->comps_obj);
859         if ((!arches2) || (__comps_objlist_intersected(arches, arches2))) {
860             group = comps_docgroup_arch_filter((COMPS_DocGroup*)it->comps_obj,
861                                                 arches);
862             comps_doc_add_group(ret, group);
863         }
864         COMPS_OBJECT_DESTROY(arches2);
865     }
866     COMPS_OBJECT_DESTROY(list);
867     list = comps_doc_environments(source);
868     for (COMPS_ObjListIt *it = list->first; it != NULL; it = it->next) {
869         arches2 = comps_docenv_arches((COMPS_DocEnv*)it->comps_obj);
870         if ((!arches2) || (__comps_objlist_intersected(arches, arches2))) {
871             env = comps_docenv_arch_filter((COMPS_DocEnv*)it->comps_obj,
872                                            arches);
873             comps_doc_add_environment(ret, env);
874         }
875         COMPS_OBJECT_DESTROY(arches2);
876     }
877     COMPS_OBJECT_DESTROY(list);
878     return ret;
879 }
880 
881 /*COMPS_Doc* comps_doc_set_lang(COMPS_Doc *comps, const char * lang) {
882     COMPS_OBJECT_DESTROY(comps->lang);
883     comps->lang = comps_str(lang);
884 }*/
885 
comps_doc_listobjs_validate(COMPS_Object * object,COMPS_Object * objlist,COMPS_ValRuleGeneric ** rules)886 COMPS_ValGenResult* comps_doc_listobjs_validate(COMPS_Object *object,
887                                                 COMPS_Object *objlist,
888                                                 COMPS_ValRuleGeneric** rules) {
889     (void)object;
890     COMPS_ValGenResult *valres = NULL, *tmpres;
891     size_t x = 0;
892     char *str;
893     for (COMPS_ObjListIt *it = ((COMPS_ObjList*)objlist)->first;
894          it != NULL;
895          it = it->next, x++) {
896         tmpres = comps_validate_execute(it->comps_obj, rules);
897         if (tmpres->obj_info == &COMPS_ValErrResult_ObjInfo) {
898             if (!valres) {
899                 valres = (COMPS_ValGenResult*)
900                          COMPS_OBJECT_CREATE(COMPS_ValErrResult, NULL);
901             }
902             str = malloc(digits_count(x)*(sizeof(char)+2));
903             sprintf(str, "%zu.", x);
904             comps_valgenres_prefix(tmpres, str);
905             free(str);
906             comps_valgenres_concat(&valres, tmpres);
907         }
908         COMPS_OBJECT_DESTROY(tmpres);
909     }
910     if (!valres) {
911         valres = (COMPS_ValGenResult*)COMPS_OBJECT_CREATE(COMPS_ValOkResult,
912                                                           NULL);
913     }
914     return valres;
915 }
916 
comps_docgroups_validate(COMPS_Object * object,COMPS_Object * objlist)917 COMPS_ValGenResult* comps_docgroups_validate(COMPS_Object *object,
918                                              COMPS_Object *objlist) {
919     return comps_doc_listobjs_validate(object, objlist,
920                                        COMPS_DocGroup_ValidateRules);
921 }
comps_doccategories_validate(COMPS_Object * object,COMPS_Object * objlist)922 COMPS_ValGenResult* comps_doccategories_validate(COMPS_Object *object,
923                                              COMPS_Object *objlist) {
924     return comps_doc_listobjs_validate(object, objlist,
925                                        COMPS_DocCategory_ValidateRules);
926 }
comps_docenvs_validate(COMPS_Object * object,COMPS_Object * objlist)927 COMPS_ValGenResult* comps_docenvs_validate(COMPS_Object *object,
928                                              COMPS_Object *objlist) {
929     return comps_doc_listobjs_validate(object, objlist,
930                                        COMPS_DocEnv_ValidateRules);
931 }
932 
933 COMPS_ValRuleGeneric* COMPS_Doc_ValidateRules[] = {
934     (COMPS_ValRuleGeneric*)&(COMPS_ValRuleList2){COMPS_VAL_RULE_LIST2,
935                          .verbose_msg = "Groups check:",
936                          .get_f = (COMPS_Object*(*)(COMPS_Object*))comps_doc_groups,
937                          .check_f = &comps_docgroups_validate},
938     (COMPS_ValRuleGeneric*)&(COMPS_ValRuleList2){COMPS_VAL_RULE_LIST2,
939                          .verbose_msg = "Categories check:",
940                          .get_f = (COMPS_Object*(*)(COMPS_Object*))comps_doc_categories,
941                          .check_f = &comps_doccategories_validate},
942     (COMPS_ValRuleGeneric*)&(COMPS_ValRuleList2){COMPS_VAL_RULE_LIST2,
943                          .verbose_msg = "Environments check:",
944                          .get_f = (COMPS_Object*(*)(COMPS_Object*))
945                                                    comps_doc_environments,
946                          .check_f = &comps_docenvs_validate},
947     NULL
948 };
949 
950 COMPS_ObjectInfo COMPS_Doc_ObjInfo = {
951     .obj_size = sizeof(COMPS_Doc),
952     .constructor = &comps_doc_create_u,
953     .destructor = &comps_doc_destroy_u,
954     .copy = &comps_doc_copy_u,
955     .obj_cmp = &comps_doc_cmp_u
956 };
957