- add solvable allocation functions
[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 static int
21 split(char *l, char **sp, int m)
22 {
23   int i;
24   for (i = 0; i < m;)
25     {
26       while (*l == ' ' || *l == '\t')
27         l++;
28       if (!*l)
29         break;
30       sp[i++] = l;
31       if (i == m)
32         break;
33       while (*l && !(*l == ' ' || *l == '\t'))
34         l++;
35       if (!*l)
36         break;
37       *l++ = 0;
38     }
39   return i;
40 }
41
42 struct parsedata {
43   char *kind;
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       if (!pd->tmp)
82         pd->tmp = malloc(pd->tmpl);
83       else
84         pd->tmp = realloc(pd->tmp, pd->tmpl);
85     }
86   p = pd->tmp;
87   if (s1)
88     {
89       strcpy(p, s1);
90       p += strlen(s1);
91     }
92   if (s2)
93     {
94       strcpy(p, s2);
95       p += strlen(s2);
96     }
97   if (s3)
98     {
99       strcpy(p, s3);
100       p += strlen(s3);
101     }
102   return pd->tmp;
103 }
104
105 static unsigned int
106 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, int isreq)
107 {
108   int flags, words;
109   Id id, evrid;
110   char *sp[4];
111
112   words = 0;
113   while (1)
114     {
115       /* Name [relop evr [rest]] --> 1, 3 or 4 fields.  */
116       words += split(line, sp + words, 4 - words);
117       if (words == 2)
118         {
119           fprintf(stderr, "Bad dependency line: %s\n", line);
120           exit(1);
121         }
122       line = 0;
123       /* Hack, as the content file adds 'package:' for package
124          dependencies sometimes.  */
125       if (!strncmp (sp[0], "package:", 8))
126         sp[0] += 8;
127       id = str2id(pool, sp[0], 1);
128       if (words >= 3 && strpbrk (sp[1], "<>="))
129         {
130           evrid = makeevr(pool, sp[2]);
131           for (flags = 0; flags < 6; flags++)
132             if (!strcmp(sp[1], flagtab[flags]))
133               break;
134           if (flags == 6)
135             {
136               fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
137               exit(1);
138             }
139           id = rel2id(pool, id, evrid, flags + 1, 1);
140           /* Consume three words, there's nothing to move to front.  */
141           if (words == 4)
142             line = sp[3], words = 0;
143         }
144       else
145         {
146           int j;
147           /* Consume one word.  If we had more move them to front.  */
148           words--;
149           for (j = 0; j < words; j++)
150             sp[j] = sp[j+1];
151           if (words == 3)
152             line = sp[2], words = 2;
153         }
154       olddeps = repo_addid_dep(pd->repo, olddeps, id, isreq);
155       if (!line)
156         break;
157     }
158   return olddeps;
159 }
160
161 void
162 repo_add_content(Repo *repo, FILE *fp)
163 {
164   Pool *pool = repo->pool;
165   char *line, *linep;
166   int aline;
167   Solvable *s;
168   Id id;
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               id = repo_add_solvable(repo);
221               s = pool->solvables + id;
222               s->repo = repo;
223               repo->nsolvables++;
224               s->name = str2id(pool, join(&pd, pd.kind, ":", value), 1);
225             }
226           else if (istag ("VERSION"))
227             /* without a release? but that's like zypp implements it */
228             s->evr = makeevr(pool, value);
229           else if (istag ("DISTPRODUCT"))
230             ; /* DISTPRODUCT is only for Yast, not the package manager */
231           else if (istag ("DISTVERSION"))
232             ; /* DISTVERSION is only for Yast, not the package manager */
233           else if (istag ("VENDOR"))
234             s->vendor = str2id(pool, value, 1);
235           else if (istag ("ARCH"))
236             /* Theoretically we want to have the best arch of the given
237                modifiers which still is compatible with the system
238                arch.  We don't know the latter here, though.  */
239             s->arch = ARCH_NOARCH;
240           else if (istag ("PREREQUIRES"))
241             s->requires = adddep(pool, &pd, s->requires, value, 2);
242           else if (istag ("REQUIRES"))
243             s->requires = adddep(pool, &pd, s->requires, value, 1);
244           else if (istag ("PROVIDES"))
245             s->provides = adddep(pool, &pd, s->provides, value, 0);
246           else if (istag ("CONFLICTS"))
247             s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
248           else if (istag ("OBSOLETES"))
249             s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
250           else if (istag ("RECOMMENDS"))
251             s->recommends = adddep(pool, &pd, s->recommends, value, 0);
252           else if (istag ("SUGGESTS"))
253             s->suggests = adddep(pool, &pd, s->suggests, value, 0);
254           else if (istag ("SUPPLEMENTS"))
255             s->supplements = adddep(pool, &pd, s->supplements, value, 0);
256           else if (istag ("ENHANCES"))
257             s->enhances = adddep(pool, &pd, s->enhances, value, 0);
258           /* FRESHENS doesn't seem to exist.  */
259           /* XXX do something about LINGUAS and ARCH? */
260 #undef istag
261         }
262       else
263         fprintf (stderr, "malformed line: %s\n", line);
264     }
265
266   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
267     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
268   if (s)
269     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
270     
271   if (pd.tmp)
272     free(pd.tmp);
273   free(line);
274 }