Imported Upstream version 0.7.17
[platform/upstream/libsolv.git] / ext / repo_comps.c
1 /*
2  * repo_comps.c
3  *
4  * Parses RedHat comps format
5  *
6  * Copyright (c) 2012, Novell Inc.
7  *
8  * This program is licensed under the BSD license, read LICENSE.BSD
9  * for further information
10  */
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19
20 #include "pool.h"
21 #include "repo.h"
22 #include "util.h"
23 #include "solv_xmlparser.h"
24 #define DISABLE_SPLIT
25 #include "tools_util.h"
26 #include "repo_comps.h"
27
28 /*
29  * TODO:
30  *
31  * what's the difference between group/category?
32  *
33  * maybe handle REL_COND in solver recommends handling?
34  */
35
36 enum state {
37   STATE_START,
38   STATE_COMPS,
39   STATE_GROUP,
40   STATE_ID,
41   STATE_NAME,
42   STATE_DESCRIPTION,
43   STATE_DISPLAY_ORDER,
44   STATE_DEFAULT,
45   STATE_LANGONLY,
46   STATE_LANG_ONLY,
47   STATE_USERVISIBLE,
48   STATE_PACKAGELIST,
49   STATE_PACKAGEREQ,
50   STATE_CATEGORY,
51   STATE_CID,
52   STATE_CNAME,
53   STATE_CDESCRIPTION,
54   STATE_CDISPLAY_ORDER,
55   STATE_GROUPLIST,
56   STATE_GROUPID,
57   NUMSTATES
58 };
59
60 static struct solv_xmlparser_element stateswitches[] = {
61   { STATE_START,       "comps",         STATE_COMPS,         0 },
62   { STATE_COMPS,       "group",         STATE_GROUP,         0 },
63   { STATE_COMPS,       "category",      STATE_CATEGORY,      0 },
64   { STATE_GROUP,       "id",            STATE_ID,            1 },
65   { STATE_GROUP,       "name",          STATE_NAME,          1 },
66   { STATE_GROUP,       "description",   STATE_DESCRIPTION,   1 },
67   { STATE_GROUP,       "uservisible",   STATE_USERVISIBLE,   1 },
68   { STATE_GROUP,       "display_order", STATE_DISPLAY_ORDER, 1 },
69   { STATE_GROUP,       "default",       STATE_DEFAULT,       1 },
70   { STATE_GROUP,       "langonly",      STATE_LANGONLY,      1 },
71   { STATE_GROUP,       "lang_only",     STATE_LANG_ONLY,     1 },
72   { STATE_GROUP,       "packagelist",   STATE_PACKAGELIST,   0 },
73   { STATE_PACKAGELIST, "packagereq",    STATE_PACKAGEREQ,    1 },
74   { STATE_CATEGORY,    "id",            STATE_ID,            1 },
75   { STATE_CATEGORY,    "name",          STATE_NAME,          1 },
76   { STATE_CATEGORY,    "description",   STATE_DESCRIPTION,   1 },
77   { STATE_CATEGORY ,   "grouplist",     STATE_GROUPLIST,     0 },
78   { STATE_CATEGORY ,   "display_order", STATE_DISPLAY_ORDER, 1 },
79   { STATE_GROUPLIST,   "groupid",       STATE_GROUPID,       1 },
80   { NUMSTATES }
81 };
82
83 struct parsedata {
84   Pool *pool;
85   Repo *repo;
86   Repodata *data;
87   const char *filename;
88   const char *basename;
89
90   struct solv_xmlparser xmlp;
91   struct joindata jd;
92
93   const char *tmplang;
94   Id reqtype;
95   Id condreq;
96
97   Solvable *solvable;
98   const char *kind;
99   int isdefault;
100   int isvisible;
101   Id handle;
102 };
103
104
105 #define COMPS_DEFAULT_ISVISIBLE 1
106 #define COMPS_DEFAULT_ISDEFAULT 0
107
108 /* Return true if "true", false if "false", default_value otherwise */
109 static int
110 parse_boolean(char *content, int default_value)
111 {
112   if (!strcmp(content, "true"))
113     return 1;
114   if (!strcmp(content, "false"))
115     return 0;
116   return default_value;
117 }
118
119
120 static void
121 startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
122 {
123   struct parsedata *pd = xmlp->userdata;
124   Pool *pool = pd->pool;
125   Solvable *s;
126
127   switch(state)
128     {
129     case STATE_GROUP:
130     case STATE_CATEGORY:
131       s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
132       pd->handle = s - pool->solvables;
133       pd->kind = state == STATE_GROUP ? "group" : "category";
134       pd->isvisible = COMPS_DEFAULT_ISVISIBLE;
135       pd->isdefault = COMPS_DEFAULT_ISDEFAULT;
136       break;
137
138     case STATE_NAME:
139     case STATE_CNAME:
140     case STATE_DESCRIPTION:
141     case STATE_CDESCRIPTION:
142       pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("xml:lang", atts));
143       break;
144
145     case STATE_PACKAGEREQ:
146       {
147         const char *type = solv_xmlparser_find_attr("type", atts);
148         pd->condreq = 0;
149         pd->reqtype = SOLVABLE_RECOMMENDS;
150         if (type && !strcmp(type, "conditional"))
151           {
152             const char *requires = solv_xmlparser_find_attr("requires", atts);
153             if (requires && *requires)
154               pd->condreq = pool_str2id(pool, requires, 1);
155           }
156         else if (type && !strcmp(type, "mandatory"))
157           pd->reqtype = SOLVABLE_REQUIRES;
158         else if (type && !strcmp(type, "optional"))
159           pd->reqtype = SOLVABLE_SUGGESTS;
160         break;
161       }
162
163     default:
164       break;
165     }
166 }
167
168
169 static void
170 endElement(struct solv_xmlparser *xmlp, int state, char *content)
171 {
172   struct parsedata *pd = xmlp->userdata;
173   Solvable *s = pd->solvable;
174   Id id;
175
176   switch (state)
177     {
178     case STATE_GROUP:
179     case STATE_CATEGORY:
180       if (!s->arch)
181         s->arch = ARCH_NOARCH;
182       if (!s->evr)
183         s->evr = ID_EMPTY;
184       if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
185         s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
186       if (pd->isvisible)
187         repodata_set_void(pd->data, pd->handle, SOLVABLE_ISVISIBLE);
188       if (pd->isdefault)
189         repodata_set_void(pd->data, pd->handle, SOLVABLE_ISDEFAULT);
190       pd->solvable = 0;
191       break;
192
193     case STATE_ID:
194       s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->kind, ":", content), 1);
195       break;
196
197     case STATE_NAME:
198       repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
199       break;
200
201     case STATE_DESCRIPTION:
202       repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
203       break;
204
205     case STATE_PACKAGEREQ:
206       id = pool_str2id(pd->pool, content, 1);
207       if (pd->condreq)
208         id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1);
209       repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id);
210       break;
211
212     case STATE_GROUPID:
213       id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", content), 1);
214       s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
215       break;
216
217     case STATE_USERVISIBLE:
218       pd->isvisible = parse_boolean(content, COMPS_DEFAULT_ISVISIBLE);
219       break;
220
221     case STATE_DEFAULT:
222       pd->isdefault = parse_boolean(content, COMPS_DEFAULT_ISDEFAULT);
223       break;
224
225     case STATE_LANG_ONLY:
226       repodata_set_str(pd->data, pd->handle, SOLVABLE_LANGONLY, content);
227       break;
228
229     case STATE_LANGONLY:
230       repodata_set_str(pd->data, pd->handle, SOLVABLE_LANGONLY, content);
231       break;
232
233     case STATE_DISPLAY_ORDER:
234       repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, content);
235       break;
236
237     default:
238       break;
239     }
240 }
241
242 int
243 repo_add_comps(Repo *repo, FILE *fp, int flags)
244 {
245   Repodata *data;
246   struct parsedata pd;
247
248   data = repo_add_repodata(repo, flags);
249
250   memset(&pd, 0, sizeof(pd));
251   pd.repo = repo;
252   pd.pool = repo->pool;
253   pd.data = data;
254   solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
255   if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
256     pool_debug(pd.pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
257   solv_xmlparser_free(&pd.xmlp);
258   join_freemem(&pd.jd);
259
260   if (!(flags & REPO_NO_INTERNALIZE))
261     repodata_internalize(data);
262   return 0;
263 }
264
265 /* EOF */