describe changes
[platform/upstream/libsolv.git] / tools / repo_content.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #include <sys/types.h>
9 #include <limits.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <assert.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "util.h"
19 #include "repo_content.h"
20
21 static int
22 split(char *l, char **sp, int m)
23 {
24   int i;
25   for (i = 0; i < m;)
26     {
27       while (*l == ' ' || *l == '\t')
28         l++;
29       if (!*l)
30         break;
31       sp[i++] = l;
32       if (i == m)
33         break;
34       while (*l && !(*l == ' ' || *l == '\t'))
35         l++;
36       if (!*l)
37         break;
38       *l++ = 0;
39     }
40   return i;
41 }
42
43 struct parsedata {
44   Repo *repo;
45   char *tmp;
46   int tmpl;
47 };
48
49 static Id
50 makeevr(Pool *pool, char *s)
51 {
52   if (!strncmp(s, "0:", 2) && s[2])
53     s += 2;
54   return str2id(pool, s, 1);
55 }
56
57 static char *flagtab[] = {
58   ">",
59   "=",
60   ">=",
61   "<",
62   "!=",
63   "<="
64 };
65
66 static char *
67 join(struct parsedata *pd, char *s1, char *s2, char *s3)
68 {
69   int l = 1;
70   char *p;
71
72   if (s1)
73     l += strlen(s1);
74   if (s2)
75     l += strlen(s2);
76   if (s3)
77     l += strlen(s3);
78   if (l > pd->tmpl)
79     {
80       pd->tmpl = l + 256;
81       pd->tmp = sat_realloc(pd->tmp, pd->tmpl);
82     }
83   p = pd->tmp;
84   if (s1)
85     {
86       strcpy(p, s1);
87       p += strlen(s1);
88     }
89   if (s2)
90     {
91       strcpy(p, s2);
92       p += strlen(s2);
93     }
94   if (s3)
95     {
96       strcpy(p, s3);
97       p += strlen(s3);
98     }
99   return pd->tmp;
100 }
101
102 static unsigned int
103 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
104 {
105   int flags, words;
106   Id id, evrid;
107   char *sp[4];
108
109   words = 0;
110   while (1)
111     {
112       /* Name [relop evr] [rest] --> 1, 2, 3 or 4 fields.  */
113       if ( line )
114         {
115           words += split(line, sp + words, 4 - words);
116           line = 0;
117         }
118       /* Hack, as the content file adds 'package:' for package
119          dependencies sometimes.  */
120       if (!strncmp (sp[0], "package:", 8))
121         sp[0] += 8;
122       id = str2id(pool, sp[0], 1);
123       if (words >= 3 && strpbrk (sp[1], "<>="))
124         {
125           evrid = makeevr(pool, sp[2]);
126           for (flags = 0; flags < 6; flags++)
127             if (!strcmp(sp[1], flagtab[flags]))
128               break;
129           if (flags == 6)
130             {
131               fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
132               exit(1);
133             }
134           id = rel2id(pool, id, evrid, flags + 1, 1);
135           /* Consume three words, there's nothing to move to front.  */
136           if (words == 4)
137             line = sp[3];
138           words = 0;
139         }
140       else
141         {
142           int j;
143           /* Consume one word.  If we had more move them to front.  */
144           words--;
145           for (j = 0; j < words; j++)
146             sp[j] = sp[j+1];
147           if (words == 3)
148             line = sp[2], words = 2;
149         }
150       olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
151       if (! ( line || words > 0 ) )
152         break;
153     }
154   return olddeps;
155 }
156
157 static void
158 add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
159 {
160   char *sp[2];
161   while (value)
162     {
163       int words = split(value, sp, 2);
164       if (!words)
165         break;
166       repodata_add_poolstr_array(data, handle, name, sp[0]);
167       if (words == 1)
168         break;
169       value = sp[1];
170     }
171 }
172
173 void
174 repo_add_content(Repo *repo, FILE *fp)
175 {
176   Pool *pool = repo->pool;
177   char *line, *linep;
178   int aline;
179   Solvable *s, *firsts = 0;
180   struct parsedata pd;
181   Repodata *data;
182   Id handle = 0;
183
184   memset(&pd, 0, sizeof(pd));
185   line = sat_malloc(1024);
186   aline = 1024;
187
188   if (repo->nrepodata)
189     /* use last repodata */
190     data = repo->repodata + repo->nrepodata - 1;
191   else
192     data = repo_add_repodata(repo, 0);
193
194   pd.repo = repo;
195   linep = line;
196   s = 0;
197
198   for (;;)
199     {
200       char *fields[2];
201       if (linep - line + 16 > aline)
202         {
203           aline = linep - line;
204           line = sat_realloc(line, aline + 512);
205           linep = line + aline;
206           aline += 512;
207         }
208       if (!fgets(linep, aline - (linep - line), fp))
209         break;
210       linep += strlen(linep);
211       if (linep == line || linep[-1] != '\n')
212         continue;
213       *--linep = 0;
214       linep = line;
215       if (split (line, fields, 2) == 2)
216         {
217           char *key = fields[0];
218           char *value = fields[1];
219 #if 0
220           fprintf (stderr, "key %s, value %s\n", key, fields[1]);
221 #endif
222
223 #define istag(x) !strcmp (key, x)
224           if (istag ("PRODUCT"))
225             {
226               /* Finish old solvable, but only if it wasn't created
227                  on demand without seeing a PRODUCT entry.  */
228               if (!firsts)
229                 {
230                   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
231                     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
232                   if (s)
233                     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
234                   /* Only support one product.  */
235                   s = pool_id2solvable(pool, repo_add_solvable(repo));
236                   repodata_extend(data, s - pool->solvables);
237                   handle = repodata_get_handle(data, s - pool->solvables - repo->start);
238                 }
239               firsts = 0;
240               s->name = str2id(pool, join(&pd, "product", ":", value), 1);
241               continue;
242             }
243
244           /* Sometimes PRODUCT is not the first entry, but we need a solvable
245              from here on.  */
246           if (!s)
247             {
248               firsts = s = pool_id2solvable(pool, repo_add_solvable(repo));
249               repodata_extend(data, s - pool->solvables);
250               handle = repodata_get_handle(data, s - pool->solvables - repo->start);
251             }
252           if (istag ("VERSION"))
253             /* without a release? but that's like zypp implements it */
254             s->evr = makeevr(pool, value);
255           else if (istag ("DISTPRODUCT"))
256             /* DISTPRODUCT is for registration and Yast, not for the solver. */
257             repo_set_str(repo, s - pool->solvables, PRODUCT_DISTPRODUCT, value);
258           else if (istag ("DISTVERSION"))
259             /* DISTVERSION is for registration and Yast, not for the solver. */
260             repo_set_str(repo, s - pool->solvables, PRODUCT_DISTVERSION, value);
261           else if (istag ("VENDOR"))
262             s->vendor = str2id(pool, value, 1);
263           else if (istag ("ARCH"))
264             /* Theoretically we want to have the best arch of the given
265                modifiers which still is compatible with the system
266                arch.  We don't know the latter here, though.  */
267             s->arch = ARCH_NOARCH;
268           else if (istag ("PREREQUIRES"))
269             s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
270           else if (istag ("REQUIRES"))
271             s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
272           else if (istag ("PROVIDES"))
273             s->provides = adddep(pool, &pd, s->provides, value, 0);
274           else if (istag ("CONFLICTS"))
275             s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
276           else if (istag ("OBSOLETES"))
277             s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
278           else if (istag ("RECOMMENDS"))
279             s->recommends = adddep(pool, &pd, s->recommends, value, 0);
280           else if (istag ("SUGGESTS"))
281             s->suggests = adddep(pool, &pd, s->suggests, value, 0);
282           else if (istag ("SUPPLEMENTS"))
283             s->supplements = adddep(pool, &pd, s->supplements, value, 0);
284           else if (istag ("ENHANCES"))
285             s->enhances = adddep(pool, &pd, s->enhances, value, 0);
286           else if (istag ("DATADIR"))
287             repo_set_str(repo, s - pool->solvables, SUSETAGS_DATADIR, value);
288           /* FRESHENS doesn't seem to exist.  */
289           else if (istag ("TYPE"))
290             repo_set_str(repo, s - pool->solvables, PRODUCT_TYPE, value);
291           else if (istag ("RELNOTESURL"))
292             repodata_add_poolstr_array(data, handle, PRODUCT_RELNOTESURL, value);
293           else if (istag ("UPDATEURLS"))
294             add_multiple_strings(data, handle, PRODUCT_UPDATEURLS, value);
295           else if (istag ("EXTRAURLS"))
296             add_multiple_strings(data, handle, PRODUCT_EXTRAURLS, value);
297           else if (istag ("OPTIONALURLS"))
298             add_multiple_strings(data, handle, PRODUCT_OPTIONALURLS, value);
299           else if (istag ("SHORTLABEL"))
300             repo_set_str(repo, s - pool->solvables, PRODUCT_SHORTLABEL, value);
301           else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
302             repo_set_str(repo, s - pool->solvables, SOLVABLE_SUMMARY, value);
303           else if (!strncmp (key, "LABEL.", 6))
304             repo_set_str(repo, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
305           else if (istag ("FLAGS"))
306             add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
307
308           /* XXX do something about LINGUAS and ARCH?
309           * <ma>: Don't think so. zypp does not use or propagate them.
310           */
311 #undef istag
312         }
313       else
314         fprintf (stderr, "malformed line: %s\n", line);
315     }
316
317   if (!s->arch)
318     s->arch = ARCH_NOARCH;
319   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
320     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
321   if (s)
322     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
323
324   if (pd.tmp)
325     sat_free(pd.tmp);
326   sat_free(line);
327 }