- cleanup repo handlin API
[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 "util.h"
18 #include "repo_content.h"
19
20 #define PACK_BLOCK 16
21
22 static int
23 split(char *l, char **sp, int m)
24 {
25   int i;
26   for (i = 0; i < m;)
27     {
28       while (*l == ' ' || *l == '\t')
29         l++;
30       if (!*l)
31         break;
32       sp[i++] = l;
33       if (i == m)
34         break;
35       while (*l && !(*l == ' ' || *l == '\t'))
36         l++;
37       if (!*l)
38         break;
39       *l++ = 0;
40     }
41   return i;
42 }
43
44 struct parsedata {
45   char *kind;
46   Repo *repo;
47   char *tmp;
48   int tmpl;
49 };
50
51 static Id
52 makeevr(Pool *pool, char *s)
53 {
54   if (!strncmp(s, "0:", 2) && s[2])
55     s += 2;
56   return str2id(pool, s, 1);
57 }
58
59 static char *flagtab[] = {
60   ">",
61   "=",
62   ">=",
63   "<",
64   "!=",
65   "<="
66 };
67
68 static char *
69 join(struct parsedata *pd, char *s1, char *s2, char *s3)
70 {
71   int l = 1;
72   char *p;
73
74   if (s1)
75     l += strlen(s1);
76   if (s2)
77     l += strlen(s2);
78   if (s3)
79     l += strlen(s3);
80   if (l > pd->tmpl)
81     {
82       pd->tmpl = l + 256;
83       if (!pd->tmp)
84         pd->tmp = malloc(pd->tmpl);
85       else
86         pd->tmp = realloc(pd->tmp, pd->tmpl);
87     }
88   p = pd->tmp;
89   if (s1)
90     {
91       strcpy(p, s1);
92       p += strlen(s1);
93     }
94   if (s2)
95     {
96       strcpy(p, s2);
97       p += strlen(s2);
98     }
99   if (s3)
100     {
101       strcpy(p, s3);
102       p += strlen(s3);
103     }
104   return pd->tmp;
105 }
106
107 static unsigned int
108 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, int isreq)
109 {
110   int flags, words;
111   Id id, evrid;
112   char *sp[4];
113
114   words = 0;
115   while (1)
116     {
117       /* Name [relop evr [rest]] --> 1, 3 or 4 fields.  */
118       words += split(line, sp + words, 4 - words);
119       if (words == 2)
120         {
121           fprintf(stderr, "Bad dependency line: %s\n", line);
122           exit(1);
123         }
124       line = 0;
125       /* Hack, as the content file adds 'package:' for package
126          dependencies sometimes.  */
127       if (!strncmp (sp[0], "package:", 8))
128         sp[0] += 8;
129       id = str2id(pool, sp[0], 1);
130       if (words >= 3 && strpbrk (sp[1], "<>="))
131         {
132           evrid = makeevr(pool, sp[2]);
133           for (flags = 0; flags < 6; flags++)
134             if (!strcmp(sp[1], flagtab[flags]))
135               break;
136           if (flags == 6)
137             {
138               fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
139               exit(1);
140             }
141           id = rel2id(pool, id, evrid, flags + 1, 1);
142           /* Consume three words, there's nothing to move to front.  */
143           if (words == 4)
144             line = sp[3], words = 0;
145         }
146       else
147         {
148           int j;
149           /* Consume one word.  If we had more move them to front.  */
150           words--;
151           for (j = 0; j < words; j++)
152             sp[j] = sp[j+1];
153           if (words == 3)
154             line = sp[2], words = 2;
155         }
156       olddeps = repo_addid_dep(pd->repo, olddeps, id, isreq);
157       if (!line)
158         break;
159     }
160   return olddeps;
161 }
162
163 void
164 repo_add_content(Repo *repo, FILE *fp)
165 {
166   Pool *pool = repo->pool;
167   char *line, *linep;
168   int aline;
169   Solvable *s;
170   int pack;
171   struct parsedata pd;
172
173   memset(&pd, 0, sizeof(pd));
174   line = xmalloc(1024);
175   aline = 1024;
176
177   pd.repo = repo;
178   linep = line;
179   pack = 0;
180   s = 0;
181
182   for (;;)
183     {
184       char *fields[2];
185       if (linep - line + 16 > aline)
186         {
187           aline = linep - line;
188           line = realloc(line, aline + 512);
189           linep = line + aline;
190           aline += 512;
191         }
192       if (!fgets(linep, aline - (linep - line), fp))
193         break;
194       linep += strlen(linep);
195       if (linep == line || linep[-1] != '\n')
196         continue;
197       *--linep = 0;
198       linep = line;
199       if (split (line, fields, 2) == 2)
200         {
201           char *key = fields[0];
202           char *value = fields[1];
203           char *modifier = strchr (key, '.');
204           if (modifier)
205             *modifier++ = 0;
206 #if 0
207           if (modifier)
208             fprintf (stderr, "key %s, mod %s, value %s\n", key, modifier, fields[1]);
209           else
210             fprintf (stderr, "key %s, value %s\n", key, fields[1]);
211 #endif
212
213 #define istag(x) !strcmp (key, x)
214           if (istag ("PRODUCT"))
215             {
216               if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
217                 s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
218               if (s)
219                 s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
220               /* Only support one product.  */
221               pd.kind = "product";
222               if ((pack & PACK_BLOCK) == 0)
223                 {
224                   pool->solvables = realloc(pool->solvables, (pool->nsolvables + pack + PACK_BLOCK + 1) * sizeof(Solvable));
225                   memset(pool->solvables + pool->nsolvables + pack, 0, (PACK_BLOCK + 1) * sizeof(Solvable));
226                 }
227               s = pool->solvables + pool->nsolvables + pack;
228               s->repo = repo;
229               s->name = str2id(pool, join(&pd, pd.kind, ":", value), 1);
230               pack++;
231             }
232           else if (istag ("VERSION"))
233             /* without a release? but that's like zypp implements it */
234             s->evr = makeevr(pool, value);
235           else if (istag ("DISTPRODUCT"))
236             ; /* DISTPRODUCT is only for Yast, not the package manager */
237           else if (istag ("DISTVERSION"))
238             ; /* DISTVERSION is only for Yast, not the package manager */
239           else if (istag ("VENDOR"))
240             s->vendor = str2id(pool, value, 1);
241           else if (istag ("ARCH"))
242             /* Theoretically we want to have the best arch of the given
243                modifiers which still is compatible with the system
244                arch.  We don't know the latter here, though.  */
245             s->arch = ARCH_NOARCH;
246           else if (istag ("PREREQUIRES"))
247             s->requires = adddep(pool, &pd, s->requires, value, 2);
248           else if (istag ("REQUIRES"))
249             s->requires = adddep(pool, &pd, s->requires, value, 1);
250           else if (istag ("PROVIDES"))
251             s->provides = adddep(pool, &pd, s->provides, value, 0);
252           else if (istag ("CONFLICTS"))
253             s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
254           else if (istag ("OBSOLETES"))
255             s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
256           else if (istag ("RECOMMENDS"))
257             s->recommends = adddep(pool, &pd, s->recommends, value, 0);
258           else if (istag ("SUGGESTS"))
259             s->suggests = adddep(pool, &pd, s->suggests, value, 0);
260           else if (istag ("SUPPLEMENTS"))
261             s->supplements = adddep(pool, &pd, s->supplements, value, 0);
262           else if (istag ("ENHANCES"))
263             s->enhances = adddep(pool, &pd, s->enhances, value, 0);
264           /* FRESHENS doesn't seem to exist.  */
265           /* XXX do something about LINGUAS and ARCH? */
266 #undef istag
267         }
268       else
269         fprintf (stderr, "malformed line: %s\n", line);
270     }
271
272   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
273     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
274   if (s)
275     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
276     
277   pool->nsolvables += pack;
278   repo->nsolvables += pack;
279   if (pd.tmp)
280     free(pd.tmp);
281   free(line);
282 }