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