- move attributes to knownid
[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       words += split(line, sp + words, 4 - words);
114       line = 0;
115       /* Hack, as the content file adds 'package:' for package
116          dependencies sometimes.  */
117       if (!strncmp (sp[0], "package:", 8))
118         sp[0] += 8;
119       id = str2id(pool, sp[0], 1);
120       if (words >= 3 && strpbrk (sp[1], "<>="))
121         {
122           evrid = makeevr(pool, sp[2]);
123           for (flags = 0; flags < 6; flags++)
124             if (!strcmp(sp[1], flagtab[flags]))
125               break;
126           if (flags == 6)
127             {
128               fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
129               exit(1);
130             }
131           id = rel2id(pool, id, evrid, flags + 1, 1);
132           /* Consume three words, there's nothing to move to front.  */
133           if (words == 4)
134             line = sp[3], words = 0;
135         }
136       else
137         {
138           int j;
139           /* Consume one word.  If we had more move them to front.  */
140           words--;
141           for (j = 0; j < words; j++)
142             sp[j] = sp[j+1];
143           if (words == 3)
144             line = sp[2], words = 2;
145         }
146       olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
147       if (!line)
148         break;
149     }
150   return olddeps;
151 }
152
153 static void
154 add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
155 {
156   char *sp[2];
157   while (value)
158     {
159       int words = split(value, sp, 2);
160       if (!words)
161         break;
162       repodata_add_poolstr_array(data, handle, name, sp[0]);
163       if (words == 1)
164         break;
165       value = sp[1];
166     }
167 }
168
169 void
170 repo_add_content(Repo *repo, FILE *fp)
171 {
172   Pool *pool = repo->pool;
173   char *line, *linep;
174   int aline;
175   Solvable *s, *firsts = 0;
176   struct parsedata pd;
177   Repodata *data;
178   Id handle = 0;
179
180   memset(&pd, 0, sizeof(pd));
181   line = sat_malloc(1024);
182   aline = 1024;
183
184   if (repo->nrepodata)
185     /* use last repodata */
186     data = repo->repodata + repo->nrepodata - 1;
187   else
188     data = repo_add_repodata(repo, 0);
189
190   pd.repo = repo;
191   linep = line;
192   s = 0;
193
194   for (;;)
195     {
196       char *fields[2];
197       if (linep - line + 16 > aline)
198         {
199           aline = linep - line;
200           line = sat_realloc(line, aline + 512);
201           linep = line + aline;
202           aline += 512;
203         }
204       if (!fgets(linep, aline - (linep - line), fp))
205         break;
206       linep += strlen(linep);
207       if (linep == line || linep[-1] != '\n')
208         continue;
209       *--linep = 0;
210       linep = line;
211       if (split (line, fields, 2) == 2)
212         {
213           char *key = fields[0];
214           char *value = fields[1];
215           char *modifier = strchr (key, '.');
216           if (modifier)
217             *modifier++ = 0;
218 #if 0
219           if (modifier)
220             fprintf (stderr, "key %s, mod %s, value %s\n", key, modifier, fields[1]);
221           else
222             fprintf (stderr, "key %s, value %s\n", key, fields[1]);
223 #endif
224
225 #define istag(x) !strcmp (key, x)
226           if (istag ("PRODUCT"))
227             {
228               /* Finish old solvable, but only if it wasn't created
229                  on demand without seeing a PRODUCT entry.  */
230               if (!firsts)
231                 {
232                   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
233                     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
234                   if (s)
235                     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
236                   /* Only support one product.  */
237                   s = pool_id2solvable(pool, repo_add_solvable(repo));
238                   repodata_extend(data, s - pool->solvables);
239                   handle = repodata_get_handle(data, s - pool->solvables - repo->start);
240                 }
241               firsts = 0;
242               s->name = str2id(pool, join(&pd, "product", ":", value), 1);
243               continue;
244             }
245
246           /* Sometimes PRODUCT is not the first entry, but we need a solvable
247              from here on.  */
248           if (!s)
249             {
250               firsts = s = pool_id2solvable(pool, repo_add_solvable(repo));
251               repodata_extend(data, s - pool->solvables);
252               handle = repodata_get_handle(data, s - pool->solvables - repo->start);
253             }
254           if (istag ("VERSION"))
255             /* without a release? but that's like zypp implements it */
256             s->evr = makeevr(pool, value);
257           else if (istag ("DISTPRODUCT"))
258             /* DISTPRODUCT is for registration and Yast, not for the solver. */
259             repo_set_str(repo, s - pool->solvables, PRODUCT_DISTPRODUCT, value);
260           else if (istag ("DISTVERSION"))
261             /* DISTVERSION is for registration and Yast, not for the solver. */
262             repo_set_str(repo, s - pool->solvables, PRODUCT_DISTVERSION, value);
263           else if (istag ("VENDOR"))
264             s->vendor = str2id(pool, value, 1);
265           else if (istag ("ARCH"))
266             /* Theoretically we want to have the best arch of the given
267                modifiers which still is compatible with the system
268                arch.  We don't know the latter here, though.  */
269             s->arch = ARCH_NOARCH;
270           else if (istag ("PREREQUIRES"))
271             s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
272           else if (istag ("REQUIRES"))
273             s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
274           else if (istag ("PROVIDES"))
275             s->provides = adddep(pool, &pd, s->provides, value, 0);
276           else if (istag ("CONFLICTS"))
277             s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
278           else if (istag ("OBSOLETES"))
279             s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
280           else if (istag ("RECOMMENDS"))
281             s->recommends = adddep(pool, &pd, s->recommends, value, 0);
282           else if (istag ("SUGGESTS"))
283             s->suggests = adddep(pool, &pd, s->suggests, value, 0);
284           else if (istag ("SUPPLEMENTS"))
285             s->supplements = adddep(pool, &pd, s->supplements, value, 0);
286           else if (istag ("ENHANCES"))
287             s->enhances = adddep(pool, &pd, s->enhances, value, 0);
288           else if (istag ("DATADIR"))
289             repo_set_str(repo, s - pool->solvables, SUSETAGS_DATADIR, value);
290           /* FRESHENS doesn't seem to exist.  */
291           else if (istag ("TYPE"))
292             repo_set_str(repo, s - pool->solvables, PRODUCT_TYPE, value);
293           else if (istag ("RELNOTESURL"))
294             repodata_add_poolstr_array(data, handle, PRODUCT_RELNOTESURL, value);
295           else if (istag ("UPDATEURLS"))
296             add_multiple_strings(data, handle, PRODUCT_UPDATEURLS, value);
297           else if (istag ("EXTRAURLS"))
298             add_multiple_strings(data, handle, PRODUCT_EXTRAURLS, value);
299           else if (istag ("OPTIONALURLS"))
300             add_multiple_strings(data, handle, PRODUCT_OPTIONALURLS, value);
301           else if (istag ("SHORTLABEL"))
302             repo_set_str(repo, s - pool->solvables, PRODUCT_SHORTLABEL, value);
303           else if (istag ("LABEL"))
304             repo_set_str(repo, s - pool->solvables, PRODUCT_LABEL, value);
305           else if (!strncmp (key, "LABEL.", 6))
306             repo_set_str(repo, s - pool->solvables, str2id(pool, join(&pd, "product:label:", key + 6, 0), 1), value);
307           else if (istag ("FLAGS"))
308             add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
309
310           /* XXX do something about LINGUAS and ARCH? */
311 #undef istag
312         }
313       else
314         fprintf (stderr, "malformed line: %s\n", line);
315     }
316
317   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
318     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
319   if (s)
320     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
321     
322   if (pd.tmp)
323     sat_free(pd.tmp);
324   sat_free(line);
325 }