Imported Upstream version 0.6.27
[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  * handle "default" and "langonly".
33  *
34  * maybe handle REL_COND in solver recommends handling?
35  */
36
37 enum state {
38   STATE_START,
39   STATE_COMPS,
40   STATE_GROUP,
41   STATE_ID,
42   STATE_NAME,
43   STATE_DESCRIPTION,
44   STATE_DISPLAY_ORDER,
45   STATE_DEFAULT,
46   STATE_LANGONLY,
47   STATE_LANG_ONLY,
48   STATE_USERVISIBLE,
49   STATE_PACKAGELIST,
50   STATE_PACKAGEREQ,
51   STATE_CATEGORY,
52   STATE_CID,
53   STATE_CNAME,
54   STATE_CDESCRIPTION,
55   STATE_CDISPLAY_ORDER,
56   STATE_GROUPLIST,
57   STATE_GROUPID,
58   NUMSTATES
59 };
60
61 static struct solv_xmlparser_element stateswitches[] = {
62   { STATE_START,       "comps",         STATE_COMPS,         0 },
63   { STATE_COMPS,       "group",         STATE_GROUP,         0 },
64   { STATE_COMPS,       "category",      STATE_CATEGORY,      0 },
65   { STATE_GROUP,       "id",            STATE_ID,            1 },
66   { STATE_GROUP,       "name",          STATE_NAME,          1 },
67   { STATE_GROUP,       "description",   STATE_DESCRIPTION,   1 },
68   { STATE_GROUP,       "uservisible",   STATE_USERVISIBLE,   1 },
69   { STATE_GROUP,       "display_order", STATE_DISPLAY_ORDER, 1 },
70   { STATE_GROUP,       "default",       STATE_DEFAULT,       1 },
71   { STATE_GROUP,       "langonly",      STATE_LANGONLY,      1 },
72   { STATE_GROUP,       "lang_only",     STATE_LANG_ONLY,     1 },
73   { STATE_GROUP,       "packagelist",   STATE_PACKAGELIST,   0 },
74   { STATE_PACKAGELIST, "packagereq",    STATE_PACKAGEREQ,    1 },
75   { STATE_CATEGORY,    "id",            STATE_ID,            1 },
76   { STATE_CATEGORY,    "name",          STATE_NAME,          1 },
77   { STATE_CATEGORY,    "description",   STATE_DESCRIPTION,   1 },
78   { STATE_CATEGORY ,   "grouplist",     STATE_GROUPLIST,     0 },
79   { STATE_CATEGORY ,   "display_order", STATE_DISPLAY_ORDER, 1 },
80   { STATE_GROUPLIST,   "groupid",       STATE_GROUPID,       1 },
81   { NUMSTATES }
82 };
83
84 struct parsedata {
85   Pool *pool;
86   Repo *repo;
87   Repodata *data;
88   const char *filename;
89   const char *basename;
90
91   struct solv_xmlparser xmlp;
92   struct joindata jd;
93
94   const char *tmplang;
95   Id reqtype;
96   Id condreq;
97
98   Solvable *solvable;
99   const char *kind;
100   Id handle;
101 };
102
103
104
105 static void
106 startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
107 {
108   struct parsedata *pd = xmlp->userdata;
109   Pool *pool = pd->pool;
110   Solvable *s = pd->solvable;
111
112   switch(state)
113     {
114     case STATE_GROUP:
115     case STATE_CATEGORY:
116       s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
117       pd->handle = s - pool->solvables;
118       pd->kind = state == STATE_GROUP ? "group" : "category";
119       break;
120
121     case STATE_NAME:
122     case STATE_CNAME:
123     case STATE_DESCRIPTION:
124     case STATE_CDESCRIPTION:
125       pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("xml:lang", atts));
126       break;
127
128     case STATE_PACKAGEREQ:
129       {
130         const char *type = solv_xmlparser_find_attr("type", atts);
131         pd->condreq = 0;
132         pd->reqtype = SOLVABLE_RECOMMENDS;
133         if (type && !strcmp(type, "conditional"))
134           {
135             const char *requires = solv_xmlparser_find_attr("requires", atts);
136             if (requires && *requires)
137               pd->condreq = pool_str2id(pool, requires, 1);
138           }
139         else if (type && !strcmp(type, "mandatory"))
140           pd->reqtype = SOLVABLE_REQUIRES;
141         else if (type && !strcmp(type, "optional"))
142           pd->reqtype = SOLVABLE_SUGGESTS;
143         break;
144       }
145
146     default:
147       break;
148     }
149 }
150
151
152 static void
153 endElement(struct solv_xmlparser *xmlp, int state, char *content)
154 {
155   struct parsedata *pd = xmlp->userdata;
156   Solvable *s = pd->solvable;
157   Id id;
158
159   switch (state)
160     {
161     case STATE_GROUP:
162     case STATE_CATEGORY:
163       if (!s->arch)
164         s->arch = ARCH_NOARCH;
165       if (!s->evr)
166         s->evr = ID_EMPTY;
167       if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
168         s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
169       pd->solvable = 0;
170       break;
171
172     case STATE_ID:
173       s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->kind, ":", content), 1);
174       break;
175
176     case STATE_NAME:
177       repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
178       break;
179
180     case STATE_DESCRIPTION:
181       repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
182       break;
183
184     case STATE_PACKAGEREQ:
185       id = pool_str2id(pd->pool, content, 1);
186       if (pd->condreq)
187         id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1);
188       repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id);
189       break;
190
191     case STATE_GROUPID:
192       id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", content), 1);
193       s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
194       break;
195
196     case STATE_USERVISIBLE:
197       repodata_set_void(pd->data, pd->handle, SOLVABLE_ISVISIBLE);
198       break;
199
200     case STATE_DISPLAY_ORDER:
201       repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, content);
202       break;
203
204     default:
205       break;
206     }
207 }
208
209 static void
210 errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
211 {
212   struct parsedata *pd = xmlp->userdata;
213   pool_debug(pd->pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", errstr, line, column);
214 }
215
216
217 int
218 repo_add_comps(Repo *repo, FILE *fp, int flags)
219 {
220   Repodata *data;
221   struct parsedata pd;
222
223   data = repo_add_repodata(repo, flags);
224
225   memset(&pd, 0, sizeof(pd));
226   pd.repo = repo;
227   pd.pool = repo->pool;
228   pd.data = data;
229   solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
230   solv_xmlparser_parse(&pd.xmlp, fp);
231   solv_xmlparser_free(&pd.xmlp);
232   join_freemem(&pd.jd);
233
234   if (!(flags & REPO_NO_INTERNALIZE))
235     repodata_internalize(data);
236   return 0;
237 }
238
239 /* EOF */