- allow repositories that don't consist of a single block of solvables
[platform/upstream/libsolv.git] / tools / repo_susetags.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
15 #include "pool.h"
16 #include "attr_store.h"
17 #include "repo_susetags.h"
18
19 #define PACK_BLOCK 255
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 == ' ')
28         l++;
29       if (!*l)
30         break;
31       sp[i++] = l;
32       while (*l && *l != ' ')
33         l++;
34       if (!*l)
35         break;
36       *l++ = 0;
37     }
38   return i;
39 }
40
41 struct parsedata {
42   char *kind;
43   Repo *repo;
44   char *tmp;
45   int tmpl;
46 };
47
48 static Id
49 makeevr(Pool *pool, char *s)
50 {
51   if (!strncmp(s, "0:", 2) && s[2])
52     s += 2;
53   return str2id(pool, s, 1);
54 }
55
56 static char *flagtab[] = {
57   ">",
58   "=",
59   ">=",
60   "<",
61   "!=",
62   "<="
63 };
64
65 static char *
66 join(struct parsedata *pd, char *s1, char *s2, char *s3)
67 {
68   int l = 1;
69   char *p;
70
71   if (s1)
72     l += strlen(s1);
73   if (s2)
74     l += strlen(s2);
75   if (s3)
76     l += strlen(s3);
77   if (l > pd->tmpl)
78     {
79       pd->tmpl = l + 256;
80       if (!pd->tmp)
81         pd->tmp = malloc(pd->tmpl);
82       else
83         pd->tmp = realloc(pd->tmp, pd->tmpl);
84     }
85   p = pd->tmp;
86   if (s1)
87     {
88       strcpy(p, s1);
89       p += strlen(s1);
90     }
91   if (s2)
92     {
93       strcpy(p, s2);
94       p += strlen(s2);
95     }
96   if (s3)
97     {
98       strcpy(p, s3);
99       p += strlen(s3);
100     }
101   return pd->tmp;
102 }
103
104 static unsigned int
105 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, int isreq, char *kind)
106 {
107   int i, flags;
108   Id id, evrid;
109   char *sp[4];
110
111   i = split(line + 5, sp, 4);
112   if (i != 1 && i != 3)
113     {
114       fprintf(stderr, "Bad dependency line: %s\n", line);
115       exit(1);
116     }
117   if (kind)
118     id = str2id(pool, join(pd, kind, ":", sp[0]), 1);
119   else
120     id = str2id(pool, sp[0], 1);
121   if (i == 3)
122     {
123       evrid = makeevr(pool, sp[2]);
124       for (flags = 0; flags < 6; flags++)
125         if (!strcmp(sp[1], flagtab[flags]))
126           break;
127       if (flags == 6)
128         {
129           fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
130           exit(1);
131         }
132       id = rel2id(pool, id, evrid, flags + 1, 1);
133     }
134   return repo_addid_dep(pd->repo, olddeps, id, isreq);
135 }
136
137 Attrstore *attr;
138
139 void
140 repo_add_susetags(Repo *repo, FILE *fp, Id vendor, int with_attr)
141 {
142   Pool *pool = repo->pool;
143   char *line, *linep;
144   int aline;
145   Solvable *s;
146   int intag = 0;
147   int cummulate = 0;
148   int indesc = 0;
149   int last_found_pack = 0;
150   int pack;
151   char *sp[5];
152   struct parsedata pd;
153
154   if (!repo->start || repo->start == repo->end)
155     repo->start = pool->nsolvables;
156   repo->end = pool->nsolvables;
157
158   attr = new_store (pool);
159   memset(&pd, 0, sizeof(pd));
160   line = malloc(1024);
161   aline = 1024;
162
163   pd.repo = repo;
164
165   linep = line;
166   pack = 0;
167   s = 0;
168
169   for (;;)
170     {
171       if (linep - line + 16 > aline)
172         {
173           aline = linep - line;
174           line = realloc(line, aline + 512);
175           linep = line + aline;
176           aline += 512;
177         }
178       if (!fgets(linep, aline - (linep - line), fp))
179         break;
180       linep += strlen(linep);
181       if (linep == line || linep[-1] != '\n')
182         continue;
183       *--linep = 0;
184       if (intag)
185         {
186           int isend = linep[-intag - 2] == '-' && linep[-1] == ':' && !strncmp(linep - 1 - intag, line + 1, intag) && (linep == line + 1 + intag + 1 + 1 + 1 + intag + 1 || linep[-intag - 3] == '\n');
187           if (cummulate && !isend)
188             {
189               *linep++ = '\n';
190               continue;
191             }
192           if (cummulate && isend)
193             {
194               linep[-intag - 2] = 0;
195               if (linep[-intag - 3] == '\n')
196                 linep[-intag - 3] = 0;
197               linep = line;
198               intag = 0;
199             }
200           if (!cummulate && isend)
201             {
202               intag = 0;
203               linep = line;
204               continue;
205             }
206           if (!cummulate && !isend)
207             linep = line + intag + 3;
208         }
209       else
210         linep = line;
211       if (!intag && line[0] == '+' && line[1] && line[1] != ':')
212         {
213           char *tagend = strchr(line, ':');
214           if (!tagend)
215             {
216               fprintf(stderr, "bad line: %s\n", line);
217               exit(1);
218             }
219           intag = tagend - (line + 1);
220           if (!strncmp (line, "+Des:", 5))
221             cummulate = 1;
222           else if (!strncmp (line, "+Aut:", 5))
223             cummulate = 1;
224           else
225             cummulate = 0;
226           line[0] = '=';
227           line[intag + 2] = ' ';
228           linep = line + intag + 3;
229           continue;
230         }
231       if (*line == '#' || !*line)
232         continue;
233       if (indesc < 2
234           && (!strncmp(line, "=Pkg:", 5) || !strncmp(line, "=Pat:", 5)))
235         {
236           if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
237             s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
238           if (s)
239             s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
240           pd.kind = 0;
241           if (line[3] == 't')
242             pd.kind = "pattern";
243           if ((pack & PACK_BLOCK) == 0)
244             {
245               pool->solvables = realloc(pool->solvables, (pool->nsolvables + pack + PACK_BLOCK + 1) * sizeof(Solvable));
246               memset(pool->solvables + pool->nsolvables + pack, 0, (PACK_BLOCK + 1) * sizeof(Solvable));
247             }
248           s = pool->solvables + pool->nsolvables + pack;
249           s->repo = repo;
250           last_found_pack = pack;
251           pack++;
252           if (split(line + 5, sp, 5) != 4)
253             {
254               fprintf(stderr, "Bad line: %s\n", line);
255               exit(1);
256             }
257           if (pd.kind)
258             s->name = str2id(pool, join(&pd, pd.kind, ":", sp[0]), 1);
259           else
260             s->name = str2id(pool, sp[0], 1);
261           s->evr = makeevr(pool, join(&pd, sp[1], "-", sp[2]));
262           s->arch = str2id(pool, sp[3], 1);
263           s->vendor = vendor;
264           continue;
265         }
266       if (indesc == 2
267           && (!strncmp(line, "=Pkg:", 5) || !strncmp(line, "=Pat:", 5)))
268         {
269           Id name, evr, arch;
270           int n, nn;
271           pd.kind = 0;
272           if (line[3] == 't')
273             pd.kind = "pattern";
274           if (split(line + 5, sp, 5) != 4)
275             {
276               fprintf(stderr, "Bad line: %s\n", line);
277               exit(1);
278             }
279           s = 0;
280           if (pd.kind)
281             name = str2id(pool, join(&pd, pd.kind, ":", sp[0]), 0);
282           else
283             name = str2id(pool, sp[0], 0);
284           evr = makeevr(pool, join(&pd, sp[1], "-", sp[2]));
285           arch = str2id(pool, sp[3], 0);
286           /* If we found neither the name of the arch at all in this repo
287              there's no chance of finding the exact solvable either.  */
288           if (!name || !arch)
289             continue;
290           /* Now look for a solvable with the given name,evr,arch.
291              Our input is structured so, that the second set of =Pkg
292              lines comes in roughly the same order as the first set, so we 
293              have a hint at where to start our search, namely were we found
294              the last entry.  */
295           for (n = 0, nn = last_found_pack; n < pack; n++, nn++)
296             {
297               if (nn >= pack)
298                 nn = 0;
299               s = pool->solvables + pool->nsolvables + nn;
300               if (s->name == name && s->evr == evr && s->arch == arch)
301                 break;
302             }
303           if (n == pack)
304             s = 0;
305           else
306             last_found_pack = nn;
307           continue;
308         }
309       /* If we have no current solvable to add to, ignore all further lines
310          for it.  Probably invalid input data in the second set of
311          solvables.  */
312       if (indesc >= 2 && !s)
313         {
314           fprintf (stderr, "Huh?\n");
315           continue;
316         }
317       if (!strncmp(line, "=Prv:", 5))
318         {
319           s->provides = adddep(pool, &pd, s->provides, line, 0, pd.kind);
320           continue;
321         }
322       if (!strncmp(line, "=Req:", 5))
323         {
324           s->requires = adddep(pool, &pd, s->requires, line, 1, pd.kind);
325           continue;
326         }
327       if (!strncmp(line, "=Prq:", 5))
328         {
329           if (pd.kind)
330             s->requires = adddep(pool, &pd, s->requires, line, 0, 0);
331           else
332             s->requires = adddep(pool, &pd, s->requires, line, 2, 0);
333           continue;
334         }
335       if (!strncmp(line, "=Obs:", 5))
336         {
337           s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, pd.kind);
338           continue;
339         }
340       if (!strncmp(line, "=Con:", 5))
341         {
342           s->conflicts = adddep(pool, &pd, s->conflicts, line, 0, pd.kind);
343           continue;
344         }
345       if (!strncmp(line, "=Rec:", 5))
346         {
347           s->recommends = adddep(pool, &pd, s->recommends, line, 0, pd.kind);
348           continue;
349         }
350       if (!strncmp(line, "=Sup:", 5))
351         {
352           s->supplements = adddep(pool, &pd, s->supplements, line, 0, pd.kind);
353           continue;
354         }
355       if (!strncmp(line, "=Enh:", 5))
356         {
357           s->enhances = adddep(pool, &pd, s->enhances, line, 0, pd.kind);
358           continue;
359         }
360       if (!strncmp(line, "=Sug:", 5))
361         {
362           s->suggests = adddep(pool, &pd, s->suggests, line, 0, pd.kind);
363           continue;
364         }
365       if (!strncmp(line, "=Fre:", 5))
366         {
367           s->freshens = adddep(pool, &pd, s->freshens, line, 0, pd.kind);
368           continue;
369         }
370       if (!strncmp(line, "=Prc:", 5))
371         {
372           s->recommends = adddep(pool, &pd, s->recommends, line, 0, 0);
373           continue;
374         }
375       if (!strncmp(line, "=Psg:", 5))
376         {
377           s->suggests = adddep(pool, &pd, s->suggests, line, 0, 0);
378           continue;
379         }
380       if (!with_attr)
381         continue;
382       if (!strncmp(line, "=Grp:", 5))
383         {
384           ensure_entry (attr, last_found_pack);
385           add_attr_localids_id (attr, last_found_pack, str2nameid (attr, "group"), str2localid (attr, line + 6, 1));
386           continue;
387         }
388       if (!strncmp(line, "=Lic:", 5))
389         {
390           ensure_entry (attr, last_found_pack);
391           add_attr_localids_id (attr, last_found_pack, str2nameid (attr, "license"), str2localid (attr, line + 6, 1));
392           continue;
393         }
394       if (!strncmp(line, "=Kwd:", 5))
395         {
396           ensure_entry (attr, last_found_pack);
397           add_attr_localids_id (attr, last_found_pack, str2nameid (attr, "keywords"), str2localid (attr, line + 6, 1));
398           continue;
399         }
400       if (!strncmp(line, "=Aut:", 5))
401         {
402           ensure_entry (attr, last_found_pack);
403           add_attr_blob (attr, last_found_pack, str2nameid (attr, "authors"), line + 6, strlen (line + 6) + 1);
404           continue;
405         }
406       if (!strncmp(line, "=Sum:", 5))
407         {
408           ensure_entry (attr, last_found_pack);
409           add_attr_string (attr, last_found_pack, str2nameid (attr, "summary"), line + 6);
410           continue;
411         }
412       if (!strncmp(line, "=Des:", 5))
413         {
414           ensure_entry (attr, last_found_pack);
415           add_attr_blob (attr, last_found_pack, str2nameid (attr, "description"), line + 6, strlen (line + 6) + 1);
416           continue;
417         }
418       if (!strncmp(line, "=Ver:", 5))
419         {
420           last_found_pack = 0;
421           indesc++;
422           continue;
423         }
424     }
425   if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
426     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
427   if (s)
428     s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
429     
430   pool->nsolvables += pack;
431   repo->nsolvables += pack;
432   repo->end += pack;
433   if (pd.tmp)
434     free(pd.tmp);
435   free(line);
436 }