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