- store location, dunno why it does not work yet
[platform/upstream/libsolv.git] / tools / repo_rpmmd.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 <expat.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "tools_util.h"
19 #include "repo_rpmmd.h"
20
21
22 enum state {
23   STATE_START,
24   STATE_METADATA,
25   STATE_SOLVABLE,
26   STATE_PRODUCT,
27   STATE_PATTERN,
28   STATE_PATCH,
29   STATE_NAME,
30   STATE_ARCH,
31   STATE_VERSION,
32
33   // package rpm-md
34   STATE_LOCATION,
35   STATE_CHECKSUM,
36
37   /* resobject attributes */
38   STATE_SUMMARY,
39   STATE_DESCRIPTION,
40   STATE_INSNOTIFY,
41   STATE_DELNOTIFY,
42   STATE_VENDOR,
43   STATE_SIZE,
44   STATE_DOWNLOADSIZE,
45   STATE_INSTALLTIME,
46   STATE_INSTALLONLY,
47   
48   /* patch */
49   STATE_ID,
50   STATE_TIMESTAMP,
51   STATE_AFFECTSPKG,
52   STATE_REBOOTNEEDED,
53
54    // xml store pattern attributes
55   STATE_CATEGORY, /* pattern and patches */
56   STATE_SCRIPT,
57   STATE_ICON,
58   STATE_USERVISIBLE,
59   STATE_DEFAULT,
60   STATE_INSTALL_TIME,
61
62   /* product */
63   STATE_SHORTNAME,
64   STATE_DISTNAME,
65   STATE_DISTEDITION,
66   STATE_SOURCE,
67   STATE_RELNOTESURL,
68
69   STATE_FORMAT,
70   
71   /* rpm-md dependencies inside the
72      format tag */
73   STATE_PROVIDES,
74   STATE_REQUIRES,
75   STATE_OBSOLETES,
76   STATE_CONFLICTS,
77   STATE_RECOMMENDS,
78   STATE_SUPPLEMENTS,
79   STATE_SUGGESTS,
80   STATE_ENHANCES,
81   STATE_FRESHENS,
82
83   STATE_CAPS_FORMAT,
84   STATE_CAPS_VENDOR,
85   STATE_CAPS_PROVIDES,
86   STATE_CAPS_REQUIRES,
87   STATE_CAPS_OBSOLETES,
88   STATE_CAPS_CONFLICTS,
89   STATE_CAPS_RECOMMENDS,
90   STATE_CAPS_SUPPLEMENTS,
91   STATE_CAPS_SUGGESTS,
92   STATE_CAPS_ENHANCES,
93   STATE_CAPS_FRESHENS,
94
95   STATE_PROVIDESENTRY,
96   STATE_REQUIRESENTRY,
97   STATE_OBSOLETESENTRY,
98   STATE_CONFLICTSENTRY,
99   STATE_RECOMMENDSENTRY,
100   STATE_SUPPLEMENTSENTRY,
101   STATE_SUGGESTSENTRY,
102   STATE_ENHANCESENTRY,
103   STATE_FRESHENSENTRY,
104
105   STATE_CAP_FRESHENS,
106   STATE_CAP_PROVIDES,
107   STATE_CAP_REQUIRES,
108   STATE_CAP_OBSOLETES,
109   STATE_CAP_CONFLICTS,
110   STATE_CAP_SUGGESTS,
111   STATE_CAP_RECOMMENDS,
112   STATE_CAP_SUPPLEMENTS,
113   STATE_CAP_ENHANCES,
114
115   STATE_FILE,
116
117   // general
118   NUMSTATES
119 };
120
121 struct stateswitch {
122   enum state from;
123   char *ename;
124   enum state to;
125   int docontent;
126 };
127
128 static struct stateswitch stateswitches[] = {
129
130   { STATE_START,       "product",         STATE_SOLVABLE, 0 },
131   { STATE_START,       "pattern",         STATE_SOLVABLE, 0 },
132   { STATE_START,       "patch",           STATE_SOLVABLE, 0 },
133
134   { STATE_START,       "metadata",        STATE_METADATA, 0 },
135   { STATE_METADATA,    "package",         STATE_SOLVABLE, 0 },
136   
137   { STATE_SOLVABLE,    "name",            STATE_NAME, 1 },
138   { STATE_SOLVABLE,    "arch",            STATE_ARCH, 1 },
139   { STATE_SOLVABLE,    "version",         STATE_VERSION, 0 },
140
141   // package attributes rpm-md
142   { STATE_SOLVABLE,    "location",            STATE_LOCATION, 0 },
143   { STATE_SOLVABLE,    "checksum",         STATE_CHECKSUM, 1 },
144   
145   /* resobject attributes */
146
147   { STATE_SOLVABLE,    "summary",         STATE_SUMMARY, 1 },
148   { STATE_SOLVABLE,    "description",     STATE_DESCRIPTION, 1 },
149   //{ STATE_SOLVABLE,    "???",         STATE_INSNOTIFY, 1 },
150   //{ STATE_SOLVABLE,    "??",     STATE_DELNOTIFY, 1 },
151   { STATE_SOLVABLE,    "vendor",          STATE_VENDOR, 1 },
152   { STATE_SOLVABLE,    "size",            STATE_SIZE, 1 },
153   { STATE_SOLVABLE,    "archive-size",    STATE_DOWNLOADSIZE, 1 },
154   { STATE_SOLVABLE,    "install-time",    STATE_INSTALLTIME, 1 },
155   { STATE_SOLVABLE,    "install-only",    STATE_INSTALLONLY, 1 },
156
157   // xml store pattern attributes
158   { STATE_SOLVABLE,    "script",          STATE_SCRIPT, 1 },
159   { STATE_SOLVABLE,    "icon",            STATE_ICON, 1 },
160   { STATE_SOLVABLE,    "uservisible",     STATE_USERVISIBLE, 1 },
161   { STATE_SOLVABLE,    "category",        STATE_CATEGORY, 1 },
162   { STATE_SOLVABLE,    "default",         STATE_DEFAULT, 1 },
163   { STATE_SOLVABLE,    "install-time",    STATE_INSTALL_TIME, 1 },
164
165   { STATE_SOLVABLE,    "format",          STATE_FORMAT, 0 },
166
167   /* those are used in libzypp xml store */
168   { STATE_SOLVABLE,    "obsoletes",       STATE_CAPS_OBSOLETES , 0 },
169   { STATE_SOLVABLE,    "conflicts",       STATE_CAPS_CONFLICTS , 0 },
170   { STATE_SOLVABLE,    "recommends",      STATE_CAPS_RECOMMENDS , 0 },
171   { STATE_SOLVABLE,    "supplements",     STATE_CAPS_SUPPLEMENTS, 0 },
172   { STATE_SOLVABLE,    "suggests",        STATE_CAPS_SUGGESTS, 0 },
173   { STATE_SOLVABLE,    "enhances",        STATE_CAPS_ENHANCES, 0 },
174   { STATE_SOLVABLE,    "freshens",        STATE_CAPS_FRESHENS, 0 },
175   { STATE_SOLVABLE,    "provides",        STATE_CAPS_PROVIDES, 0 },
176   { STATE_SOLVABLE,    "requires",        STATE_CAPS_REQUIRES, 0 },
177
178   { STATE_CAPS_PROVIDES,    "capability",      STATE_CAP_PROVIDES, 1 },
179   { STATE_CAPS_REQUIRES,    "capability",      STATE_CAP_REQUIRES, 1 },
180   { STATE_CAPS_OBSOLETES,   "capability",      STATE_CAP_OBSOLETES, 1 },
181   { STATE_CAPS_CONFLICTS,   "capability",      STATE_CAP_CONFLICTS, 1 },
182   { STATE_CAPS_RECOMMENDS,  "capability",      STATE_CAP_RECOMMENDS, 1 },
183   { STATE_CAPS_SUPPLEMENTS, "capability",      STATE_CAP_SUPPLEMENTS, 1 },
184   { STATE_CAPS_SUGGESTS,    "capability",      STATE_CAP_SUGGESTS, 1 },
185   { STATE_CAPS_ENHANCES,    "capability",      STATE_CAP_ENHANCES, 1 },
186   { STATE_CAPS_FRESHENS,    "capability",      STATE_CAP_FRESHENS, 1 },
187   
188   { STATE_FORMAT,      "rpm:vendor",      STATE_VENDOR, 1 },
189
190   /* rpm-md dependencies */ 
191   { STATE_FORMAT,      "rpm:provides",    STATE_PROVIDES, 0 },
192   { STATE_FORMAT,      "rpm:requires",    STATE_REQUIRES, 0 },
193   { STATE_FORMAT,      "rpm:obsoletes",   STATE_OBSOLETES , 0 },
194   { STATE_FORMAT,      "rpm:conflicts",   STATE_CONFLICTS , 0 },
195   { STATE_FORMAT,      "rpm:recommends",  STATE_RECOMMENDS , 0 },
196   { STATE_FORMAT,      "rpm:supplements", STATE_SUPPLEMENTS, 0 },
197   { STATE_FORMAT,      "rpm:suggests",    STATE_SUGGESTS, 0 },
198   { STATE_FORMAT,      "rpm:enhances",    STATE_ENHANCES, 0 },
199   { STATE_FORMAT,      "rpm:freshens",    STATE_FRESHENS, 0 },
200   { STATE_FORMAT,      "file",            STATE_FILE, 1 },
201   { STATE_PROVIDES,    "rpm:entry",       STATE_PROVIDESENTRY, 0 },
202   { STATE_REQUIRES,    "rpm:entry",       STATE_REQUIRESENTRY, 0 },
203   { STATE_OBSOLETES,   "rpm:entry",       STATE_OBSOLETESENTRY, 0 },
204   { STATE_CONFLICTS,   "rpm:entry",       STATE_CONFLICTSENTRY, 0 },
205   { STATE_RECOMMENDS,  "rpm:entry",       STATE_RECOMMENDSENTRY, 0 },
206   { STATE_SUPPLEMENTS, "rpm:entry",       STATE_SUPPLEMENTSENTRY, 0 },
207   { STATE_SUGGESTS,    "rpm:entry",       STATE_SUGGESTSENTRY, 0 },
208   { STATE_ENHANCES,    "rpm:entry",       STATE_ENHANCESENTRY, 0 },
209   { STATE_FRESHENS,    "rpm:entry",       STATE_FRESHENSENTRY, 0 },
210   { NUMSTATES}
211 };
212
213 struct parsedata {
214   struct parsedata_common common;
215   char *kind;
216   int depth;
217   enum state state;
218   int statedepth;
219   char *content;
220   int lcontent;
221   int acontent;
222   int docontent;
223   int numpacks;
224   Solvable *solvable;
225   Id lastsolvableid;
226   struct stateswitch *swtab[NUMSTATES];
227   enum state sbtab[NUMSTATES];
228   const char *lang;
229   const char *capkind;
230   // used to store tmp attributes
231   // while the tag ends
232   const char *tmpattr;
233   Repodata *data;
234 };
235
236 static char *flagtabnum[] = {
237   ">",
238   "=",
239   ">=",
240   "<",
241   "!=",
242   "<=",
243 };
244
245 /**
246  * adds plain dependencies, that is strings like "foo > 2.0"
247  * which are used in libzypp xml store, not in rpm-md.
248  */
249 static unsigned int
250 adddepplain(Pool *pool, struct parsedata_common *pd, unsigned int olddeps, char *line, Id marker, const char *kind)
251 {
252   int i, flags;
253   Id id, evrid;
254   char *sp[4];
255
256   i = split(line, sp, 4);
257   if (i != 1 && i != 3)
258     {
259       fprintf(stderr, "Bad dependency line: %s\n", line);
260       exit(1);
261     }
262   if (kind)
263     id = str2id(pool, join2(kind, ":", sp[0]), 1);
264   else
265     id = str2id(pool, sp[0], 1);
266   if (i == 3)
267     {
268       evrid = makeevr(pool, sp[2]);
269       for (flags = 0; flags < 6; flags++)
270         if (!strcmp(sp[1], flagtabnum[flags]))
271           break;
272       if (flags == 6)
273         {
274           if ( !strcmp(sp[1], "=="))
275            {
276             flags = 1;
277            }
278           else
279            {
280             fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
281             exit(1);
282            }
283         }
284       id = rel2id(pool, id, evrid, flags + 1, 1);
285     }
286   return repo_addid_dep(pd->repo, olddeps, id, marker);
287 }
288
289 static Id
290 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
291 {
292   const char *e, *v, *r, *v2;
293   char *c;
294   int l;
295
296   e = v = r = 0;
297   for (; *atts; atts += 2)
298     {
299       if (!strcmp(*atts, "epoch"))
300         e = atts[1];
301       else if (!strcmp(*atts, "ver"))
302         v = atts[1];
303       else if (!strcmp(*atts, "rel"))
304         r = atts[1];
305     }
306   if (e && !strcmp(e, "0"))
307     e = 0;
308   if (v && !e)
309     {
310       for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
311         ;
312       if (v2 > v && *v2 == ':')
313         e = "0";
314     }
315   l = 1;
316   if (e)
317     l += strlen(e) + 1;
318   if (v)
319     l += strlen(v);
320   if (r)
321     l += strlen(r) + 1;
322   if (l > pd->acontent)
323     {
324       pd->content = sat_realloc(pd->content, l + 256);
325       pd->acontent = l + 256;
326     }
327   c = pd->content;
328   if (e)
329     {
330       strcpy(c, e);
331       c += strlen(c);
332       *c++ = ':';
333     }
334   if (v)
335     {
336       strcpy(c, v);
337       c += strlen(c);
338     }
339   if (r)
340     {
341       *c++ = '-';
342       strcpy(c, r);
343       c += strlen(c);
344     }
345   *c = 0;
346   if (!*pd->content)
347     return 0;
348 #if 0
349   fprintf(stderr, "evr: %s\n", pd->content);
350 #endif
351   return str2id(pool, pd->content, 1);
352 }
353
354 static const char *
355 find_attr(const char *txt, const char **atts)
356 {
357   char *k;
358   k = 0;
359   for (; *atts; atts += 2)
360     {
361       if (!strcmp(*atts, txt))
362         return atts[1];
363     }
364   return k;
365 }
366
367 static char *flagtab[] = {
368   "GT",
369   "EQ",
370   "GE",
371   "LT",
372   "NE",
373   "LE"
374 };
375
376 static unsigned int
377 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq)
378 {
379   Id id, name, marker;
380   const char *n, *f, *k;
381   const char **a;
382
383   n = f = k = 0;
384   marker = isreq ? -SOLVABLE_PREREQMARKER : 0;
385   for (a = atts; *a; a += 2)
386     {
387       if (!strcmp(*a, "name"))
388         n = a[1];
389       else if (!strcmp(*a, "flags"))
390         f = a[1];
391       else if (!strcmp(*a, "kind"))
392         k = a[1];
393       else if (isreq && !strcmp(*a, "pre") && a[1][0] == '1')
394         marker = SOLVABLE_PREREQMARKER;
395     }
396   if (!n)
397     return olddeps;
398   if (k && !strcmp(k, "package"))
399     k = 0;
400   if (k)
401     {
402       int l = strlen(k) + 1 + strlen(n) + 1;
403       if (l > pd->acontent)
404         {
405           pd->content = sat_realloc(pd->content, l + 256);
406           pd->acontent = l + 256;
407         }
408       sprintf(pd->content, "%s:%s", k, n); 
409       name = str2id(pool, pd->content, 1); 
410     }
411   else
412     name = str2id(pool, (char *)n, 1);
413   if (f)
414     {
415       Id evr = makeevr_atts(pool, pd, atts);
416       int flags;
417       for (flags = 0; flags < 6; flags++)
418         if (!strcmp(f, flagtab[flags]))
419           break;
420       flags = flags < 6 ? flags + 1 : 0;
421       id = rel2id(pool, name, evr, flags, 1);
422     }
423   else
424     id = name;
425 #if 0
426   fprintf(stderr, "new dep %s%s%s\n", id2str(pool, d), id2rel(pool, d), id2evr(pool, d));
427 #endif
428   return repo_addid_dep(pd->common.repo, olddeps, id, marker);
429 }
430
431
432 static void XMLCALL
433 startElement(void *userData, const char *name, const char **atts)
434 {
435   //fprintf(stderr,"+tag: %s\n", name);
436   struct parsedata *pd = userData;
437   Pool *pool = pd->common.pool;
438   Solvable *s = pd->solvable;
439   struct stateswitch *sw;
440
441   if (pd->depth != pd->statedepth)
442     {
443       pd->depth++;
444       return;
445     }
446   pd->depth++;
447   for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
448     if (!strcmp(sw->ename, name))
449       break;
450   if (sw->from != pd->state)
451     {
452 #if 0
453       fprintf(stderr, "into unknown: %s\n", name);
454 #endif
455       return;
456     }
457   pd->state = sw->to;
458   pd->docontent = sw->docontent;
459   pd->statedepth = pd->depth;
460   pd->lcontent = 0;
461   *pd->content = 0;
462   switch(pd->state)
463     {
464     case STATE_METADATA:
465       for (; *atts; atts += 2)
466       {
467         if (!strcmp(*atts, "packages"))
468         {
469           pd->numpacks = atoi(atts[1]);
470           if (pd->numpacks < 0)
471             pd->numpacks = 0;
472 #if 0
473               fprintf(stderr, "numpacks: %d\n", pd->numpacks);
474 #endif
475             pd->solvable = pool_id2solvable(pool, repo_add_solvable_block(pd->common.repo, pd->numpacks));
476         }
477       }
478       break;
479     case STATE_SOLVABLE:
480       pd->kind = 0;
481       if ( name[2] == 't' && name[3] == 't' )
482         pd->kind = "pattern";
483       else if ( name[1] == 'r' )
484         pd->kind = "product";
485       else if ( name[2] == 't' && name[3] == 'c' )
486         pd->kind = "patch";
487       
488       if (pd->numpacks == 0)
489       {
490         pd->lastsolvableid = repo_add_solvable(pd->common.repo);
491         pd->solvable = pool_id2solvable(pool, pd->lastsolvableid);
492       }
493 #if 0
494       fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables);
495 #endif
496       break;
497     case STATE_VERSION:
498       s->evr = makeevr_atts(pool, pd, atts);
499       break;
500     case STATE_CAPS_PROVIDES:
501     case STATE_PROVIDES:
502       s->provides = 0;
503       break;
504     case STATE_PROVIDESENTRY:
505       s->provides = adddep(pool, pd, s->provides, atts, 0);
506       break;
507     case STATE_CAPS_REQUIRES:
508     case STATE_REQUIRES:
509       s->requires = 0;
510       break;
511     case STATE_REQUIRESENTRY:
512       s->requires = adddep(pool, pd, s->requires, atts, 1);
513       break;
514     case STATE_CAPS_OBSOLETES:
515     case STATE_OBSOLETES:
516       s->obsoletes = 0;
517       break;
518     case STATE_OBSOLETESENTRY:
519       s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
520       break;
521     case STATE_CAPS_CONFLICTS:
522     case STATE_CONFLICTS:
523       s->conflicts = 0;
524       break;
525     case STATE_CONFLICTSENTRY:
526       s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
527       break;
528     case STATE_CAPS_RECOMMENDS:
529     case STATE_RECOMMENDS:
530       s->recommends = 0;
531       break;
532     case STATE_RECOMMENDSENTRY:
533       s->recommends = adddep(pool, pd, s->recommends, atts, 0);
534       break;
535     case STATE_CAPS_SUPPLEMENTS:
536     case STATE_SUPPLEMENTS:
537       s->supplements= 0;
538       break;
539     case STATE_SUPPLEMENTSENTRY:
540       s->supplements = adddep(pool, pd, s->supplements, atts, 0);
541       break;
542     case STATE_CAPS_SUGGESTS:
543     case STATE_SUGGESTS:
544       s->suggests = 0;
545       break;
546     case STATE_SUGGESTSENTRY:
547       s->suggests = adddep(pool, pd, s->suggests, atts, 0);
548       break;
549     case STATE_CAPS_ENHANCES:
550     case STATE_ENHANCES:
551       s->enhances = 0;
552       break;
553     case STATE_ENHANCESENTRY:
554       s->enhances = adddep(pool, pd, s->enhances, atts, 0);
555       break;
556     case STATE_CAPS_FRESHENS:
557     case STATE_FRESHENS:
558       s->freshens = 0;
559       break;
560     case STATE_FRESHENSENTRY:
561       s->freshens = adddep(pool, pd, s->freshens, atts, 0);
562       break;
563     case STATE_CAP_PROVIDES:
564     case STATE_CAP_REQUIRES:
565     case STATE_CAP_OBSOLETES:
566     case STATE_CAP_CONFLICTS:
567     case STATE_CAP_RECOMMENDS:
568     case STATE_CAP_SUPPLEMENTS:
569     case STATE_CAP_SUGGESTS:
570     case STATE_CAP_ENHANCES:
571     case STATE_CAP_FRESHENS:
572       pd->capkind = find_attr("kind", atts);
573       //fprintf(stderr,"capkind es: %s\n", pd->capkind);
574       break;
575     case STATE_SUMMARY:
576     case STATE_DESCRIPTION:
577       pd->lang = find_attr("lang", atts);
578       //repodata_set_tstr( pd->data, pd-
579       break;
580     case STATE_LOCATION:
581       pd->tmpattr = find_attr("href", atts);
582       break;
583     case STATE_CHECKSUM:
584       pd->tmpattr = find_attr("type", atts);
585       break;
586     default:
587       break;
588     }
589 }
590
591 static void XMLCALL
592 endElement(void *userData, const char *name)
593 {
594   //fprintf(stderr,"-tag: %s\n", name);
595   struct parsedata *pd = userData;
596   Pool *pool = pd->common.pool;
597   Solvable *s = pd->solvable;
598   Repo *repo = pd->common.repo;
599   Id id;
600
601   if (pd->depth != pd->statedepth)
602     {
603       pd->depth--;
604       // printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
605       return;
606     }
607   pd->depth--;
608   pd->statedepth--;
609   switch (pd->state)
610     {
611     case STATE_PATTERN:
612     case STATE_PRODUCT:
613     case STATE_SOLVABLE:
614       if (!s->arch)
615         s->arch = ARCH_NOARCH;
616       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
617         s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
618       s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
619       if (pd->numpacks > 0)
620       {
621         pd->numpacks--;
622         pd->solvable++;
623       }
624       pd->kind = 0;
625       break;
626     case STATE_NAME:
627       if ( pd->kind )
628           s->name = str2id(pool, join2( pd->kind, ":", pd->content), 1);
629       else
630           s->name = str2id(pool, pd->content, 1);
631       break;
632     case STATE_ARCH:
633       s->arch = str2id(pool, pd->content, 1);
634       break;
635     case STATE_VENDOR:
636       s->vendor = str2id(pool, pd->content, 1);
637       break;
638     case STATE_FILE:
639       id = str2id(pool, pd->content, 1);
640       s->provides = repo_addid(repo, s->provides, id);
641       break;
642     // xml store capabilities
643     case STATE_CAP_PROVIDES:
644       s->provides = adddepplain(pool, &pd->common, s->provides, pd->content, 0, pd->capkind);
645       break;
646     case STATE_CAP_REQUIRES:
647       s->requires = adddepplain(pool, &pd->common, s->requires, pd->content, 0, pd->capkind);
648       break;
649     case STATE_CAP_OBSOLETES:
650       s->obsoletes = adddepplain(pool, &pd->common, s->obsoletes, pd->content, 0, pd->capkind);
651       break;
652     case STATE_CAP_CONFLICTS:
653       s->conflicts = adddepplain(pool, &pd->common, s->conflicts, pd->content, 0, pd->capkind);
654       break;
655     case STATE_CAP_RECOMMENDS:
656       s->recommends = adddepplain(pool, &pd->common, s->recommends, pd->content, 0, pd->capkind);
657       break;
658     case STATE_CAP_SUPPLEMENTS:
659       s->supplements = adddepplain(pool, &pd->common, s->supplements, pd->content, 0, pd->capkind);
660       break;
661     case STATE_CAP_SUGGESTS:
662       s->suggests = adddepplain(pool, &pd->common, s->suggests, pd->content, 0, pd->capkind);
663       break;
664     case STATE_CAP_ENHANCES:
665       s->enhances = adddepplain(pool, &pd->common, s->enhances, pd->content, 0, pd->capkind);
666       break;
667     case STATE_CAP_FRESHENS:
668       s->freshens = adddepplain(pool, &pd->common, s->freshens, pd->content, 0, pd->capkind);
669       break;
670     case STATE_SUMMARY:
671       pd->lang = 0;
672       break;
673     case STATE_DESCRIPTION:
674       pd->lang = 0;
675       break;
676     case STATE_LOCATION:
677       repodata_set_str(pd->data, pd->lastsolvableid, id_mediafile, pd->tmpattr);
678       break;
679     case STATE_CHECKSUM:
680       break;
681     default:
682       break;
683     }
684   pd->state = pd->sbtab[pd->state];
685   pd->docontent = 0;
686   //fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth);
687 }
688
689 static void XMLCALL
690 characterData(void *userData, const XML_Char *s, int len)
691 {
692   struct parsedata *pd = userData;
693   int l;
694   char *c;
695
696   if (!pd->docontent)
697     return;
698   l = pd->lcontent + len + 1;
699   if (l > pd->acontent)
700     {
701       pd->content = sat_realloc(pd->content, l + 256);
702       pd->acontent = l + 256;
703     }
704   c = pd->content + pd->lcontent;
705   pd->lcontent += len;
706   while (len-- > 0)
707     *c++ = *s++;
708   *c = 0;
709 }
710
711
712 #define BUFF_SIZE 8192
713
714 void
715 repo_add_rpmmd(Repo *repo, FILE *fp)
716 {
717   Pool *pool = repo->pool;
718   struct parsedata pd;
719   char buf[BUFF_SIZE];
720   int i, l;
721   struct stateswitch *sw;
722
723   memset(&pd, 0, sizeof(pd));
724   for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
725     {
726       if (!pd.swtab[sw->from])
727         pd.swtab[sw->from] = sw;
728       pd.sbtab[sw->to] = sw->from;
729     }
730   pd.common.pool = pool;
731   pd.common.repo = repo;
732
733   pd.data = repo_add_repodata(repo);
734   init_attr_ids(pool);
735
736   pd.content = sat_malloc(256);
737   pd.acontent = 256;
738   pd.lcontent = 0;
739   pd.common.tmp = 0;
740   pd.common.tmpl = 0;
741   pd.kind = 0;
742   pd.lastsolvableid = 0;
743   XML_Parser parser = XML_ParserCreate(NULL);
744   XML_SetUserData(parser, &pd);
745   XML_SetElementHandler(parser, startElement, endElement);
746   XML_SetCharacterDataHandler(parser, characterData);
747   for (;;)
748     {
749       l = fread(buf, 1, sizeof(buf), fp);
750       if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
751         {
752           fprintf(stderr, "%s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
753           exit(1);
754         }
755       if (l == 0)
756         break;
757     }
758   XML_ParserFree(parser);
759
760   if (pd.data)
761     repodata_internalize(pd.data);
762
763   if (pd.numpacks)
764     repo_free_solvable_block(repo, pd.solvable - pool->solvables, pd.numpacks, 1);
765   sat_free(pd.content);
766 }