Correct mediafile handling (and reindent some lines).
[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   struct stateswitch *swtab[NUMSTATES];
226   enum state sbtab[NUMSTATES];
227   const char *lang;
228   const char *capkind;
229   // used to store tmp attributes
230   // while the tag ends
231   const char *tmpattr;
232   Repodata *data;
233 };
234
235 static char *flagtabnum[] = {
236   ">",
237   "=",
238   ">=",
239   "<",
240   "!=",
241   "<=",
242 };
243
244 /**
245  * adds plain dependencies, that is strings like "foo > 2.0"
246  * which are used in libzypp xml store, not in rpm-md.
247  */
248 static unsigned int
249 adddepplain(Pool *pool, struct parsedata_common *pd, unsigned int olddeps, char *line, Id marker, const char *kind)
250 {
251   int i, flags;
252   Id id, evrid;
253   char *sp[4];
254
255   i = split(line, sp, 4);
256   if (i != 1 && i != 3)
257     {
258       fprintf(stderr, "Bad dependency line: %s\n", line);
259       exit(1);
260     }
261   if (kind)
262     id = str2id(pool, join2(kind, ":", sp[0]), 1);
263   else
264     id = str2id(pool, sp[0], 1);
265   if (i == 3)
266     {
267       evrid = makeevr(pool, sp[2]);
268       for (flags = 0; flags < 6; flags++)
269         if (!strcmp(sp[1], flagtabnum[flags]))
270           break;
271       if (flags == 6)
272         {
273           if ( !strcmp(sp[1], "=="))
274            {
275             flags = 1;
276            }
277           else
278            {
279             fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
280             exit(1);
281            }
282         }
283       id = rel2id(pool, id, evrid, flags + 1, 1);
284     }
285   return repo_addid_dep(pd->repo, olddeps, id, marker);
286 }
287
288 static Id
289 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
290 {
291   const char *e, *v, *r, *v2;
292   char *c;
293   int l;
294
295   e = v = r = 0;
296   for (; *atts; atts += 2)
297     {
298       if (!strcmp(*atts, "epoch"))
299         e = atts[1];
300       else if (!strcmp(*atts, "ver"))
301         v = atts[1];
302       else if (!strcmp(*atts, "rel"))
303         r = atts[1];
304     }
305   if (e && !strcmp(e, "0"))
306     e = 0;
307   if (v && !e)
308     {
309       for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
310         ;
311       if (v2 > v && *v2 == ':')
312         e = "0";
313     }
314   l = 1;
315   if (e)
316     l += strlen(e) + 1;
317   if (v)
318     l += strlen(v);
319   if (r)
320     l += strlen(r) + 1;
321   if (l > pd->acontent)
322     {
323       pd->content = sat_realloc(pd->content, l + 256);
324       pd->acontent = l + 256;
325     }
326   c = pd->content;
327   if (e)
328     {
329       strcpy(c, e);
330       c += strlen(c);
331       *c++ = ':';
332     }
333   if (v)
334     {
335       strcpy(c, v);
336       c += strlen(c);
337     }
338   if (r)
339     {
340       *c++ = '-';
341       strcpy(c, r);
342       c += strlen(c);
343     }
344   *c = 0;
345   if (!*pd->content)
346     return 0;
347 #if 0
348   fprintf(stderr, "evr: %s\n", pd->content);
349 #endif
350   return str2id(pool, pd->content, 1);
351 }
352
353 static const char *
354 find_attr(const char *txt, const char **atts)
355 {
356   char *k;
357   k = 0;
358   for (; *atts; atts += 2)
359     {
360       if (!strcmp(*atts, txt))
361         return atts[1];
362     }
363   return k;
364 }
365
366 static char *flagtab[] = {
367   "GT",
368   "EQ",
369   "GE",
370   "LT",
371   "NE",
372   "LE"
373 };
374
375 static unsigned int
376 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq)
377 {
378   Id id, name, marker;
379   const char *n, *f, *k;
380   const char **a;
381
382   n = f = k = 0;
383   marker = isreq ? -SOLVABLE_PREREQMARKER : 0;
384   for (a = atts; *a; a += 2)
385     {
386       if (!strcmp(*a, "name"))
387         n = a[1];
388       else if (!strcmp(*a, "flags"))
389         f = a[1];
390       else if (!strcmp(*a, "kind"))
391         k = a[1];
392       else if (isreq && !strcmp(*a, "pre") && a[1][0] == '1')
393         marker = SOLVABLE_PREREQMARKER;
394     }
395   if (!n)
396     return olddeps;
397   if (k && !strcmp(k, "package"))
398     k = 0;
399   if (k)
400     {
401       int l = strlen(k) + 1 + strlen(n) + 1;
402       if (l > pd->acontent)
403         {
404           pd->content = sat_realloc(pd->content, l + 256);
405           pd->acontent = l + 256;
406         }
407       sprintf(pd->content, "%s:%s", k, n); 
408       name = str2id(pool, pd->content, 1); 
409     }
410   else
411     name = str2id(pool, (char *)n, 1);
412   if (f)
413     {
414       Id evr = makeevr_atts(pool, pd, atts);
415       int flags;
416       for (flags = 0; flags < 6; flags++)
417         if (!strcmp(f, flagtab[flags]))
418           break;
419       flags = flags < 6 ? flags + 1 : 0;
420       id = rel2id(pool, name, evr, flags, 1);
421     }
422   else
423     id = name;
424 #if 0
425   fprintf(stderr, "new dep %s%s%s\n", id2str(pool, d), id2rel(pool, d), id2evr(pool, d));
426 #endif
427   return repo_addid_dep(pd->common.repo, olddeps, id, marker);
428 }
429
430
431 static void XMLCALL
432 startElement(void *userData, const char *name, const char **atts)
433 {
434   //fprintf(stderr,"+tag: %s\n", name);
435   struct parsedata *pd = userData;
436   Pool *pool = pd->common.pool;
437   Solvable *s = pd->solvable;
438   struct stateswitch *sw;
439
440   if (pd->depth != pd->statedepth)
441     {
442       pd->depth++;
443       return;
444     }
445   pd->depth++;
446   for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
447     if (!strcmp(sw->ename, name))
448       break;
449   if (sw->from != pd->state)
450     {
451 #if 0
452       fprintf(stderr, "into unknown: %s\n", name);
453 #endif
454       return;
455     }
456   pd->state = sw->to;
457   pd->docontent = sw->docontent;
458   pd->statedepth = pd->depth;
459   pd->lcontent = 0;
460   *pd->content = 0;
461   switch(pd->state)
462     {
463     case STATE_METADATA:
464       for (; *atts; atts += 2)
465         {
466           if (!strcmp(*atts, "packages"))
467             {
468               pd->numpacks = atoi(atts[1]);
469               if (pd->numpacks < 0)
470                 pd->numpacks = 0;
471 #if 0
472               fprintf(stderr, "numpacks: %d\n", pd->numpacks);
473 #endif
474               pd->solvable = pool_id2solvable(pool, repo_add_solvable_block(pd->common.repo, pd->numpacks));
475             }
476         }
477       break;
478     case STATE_SOLVABLE:
479       pd->kind = 0;
480       if (name[2] == 't' && name[3] == 't')
481         pd->kind = "pattern";
482       else if (name[1] == 'r')
483         pd->kind = "product";
484       else if (name[2] == 't' && name[3] == 'c')
485         pd->kind = "patch";
486       
487       if (pd->numpacks == 0)
488         pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->common.repo));
489 #if 0
490       fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables);
491 #endif
492       break;
493     case STATE_VERSION:
494       s->evr = makeevr_atts(pool, pd, atts);
495       break;
496     case STATE_CAPS_PROVIDES:
497     case STATE_PROVIDES:
498       s->provides = 0;
499       break;
500     case STATE_PROVIDESENTRY:
501       s->provides = adddep(pool, pd, s->provides, atts, 0);
502       break;
503     case STATE_CAPS_REQUIRES:
504     case STATE_REQUIRES:
505       s->requires = 0;
506       break;
507     case STATE_REQUIRESENTRY:
508       s->requires = adddep(pool, pd, s->requires, atts, 1);
509       break;
510     case STATE_CAPS_OBSOLETES:
511     case STATE_OBSOLETES:
512       s->obsoletes = 0;
513       break;
514     case STATE_OBSOLETESENTRY:
515       s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
516       break;
517     case STATE_CAPS_CONFLICTS:
518     case STATE_CONFLICTS:
519       s->conflicts = 0;
520       break;
521     case STATE_CONFLICTSENTRY:
522       s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
523       break;
524     case STATE_CAPS_RECOMMENDS:
525     case STATE_RECOMMENDS:
526       s->recommends = 0;
527       break;
528     case STATE_RECOMMENDSENTRY:
529       s->recommends = adddep(pool, pd, s->recommends, atts, 0);
530       break;
531     case STATE_CAPS_SUPPLEMENTS:
532     case STATE_SUPPLEMENTS:
533       s->supplements= 0;
534       break;
535     case STATE_SUPPLEMENTSENTRY:
536       s->supplements = adddep(pool, pd, s->supplements, atts, 0);
537       break;
538     case STATE_CAPS_SUGGESTS:
539     case STATE_SUGGESTS:
540       s->suggests = 0;
541       break;
542     case STATE_SUGGESTSENTRY:
543       s->suggests = adddep(pool, pd, s->suggests, atts, 0);
544       break;
545     case STATE_CAPS_ENHANCES:
546     case STATE_ENHANCES:
547       s->enhances = 0;
548       break;
549     case STATE_ENHANCESENTRY:
550       s->enhances = adddep(pool, pd, s->enhances, atts, 0);
551       break;
552     case STATE_CAPS_FRESHENS:
553     case STATE_FRESHENS:
554       s->freshens = 0;
555       break;
556     case STATE_FRESHENSENTRY:
557       s->freshens = adddep(pool, pd, s->freshens, atts, 0);
558       break;
559     case STATE_CAP_PROVIDES:
560     case STATE_CAP_REQUIRES:
561     case STATE_CAP_OBSOLETES:
562     case STATE_CAP_CONFLICTS:
563     case STATE_CAP_RECOMMENDS:
564     case STATE_CAP_SUPPLEMENTS:
565     case STATE_CAP_SUGGESTS:
566     case STATE_CAP_ENHANCES:
567     case STATE_CAP_FRESHENS:
568       pd->capkind = find_attr("kind", atts);
569       //fprintf(stderr,"capkind es: %s\n", pd->capkind);
570       break;
571     case STATE_SUMMARY:
572     case STATE_DESCRIPTION:
573       pd->lang = find_attr("lang", atts);
574       //repodata_set_tstr( pd->data, pd-
575       break;
576     case STATE_LOCATION:
577       pd->tmpattr = find_attr("href", atts);
578       break;
579     case STATE_CHECKSUM:
580       pd->tmpattr = find_attr("type", atts);
581       break;
582     default:
583       break;
584     }
585 }
586
587 static void XMLCALL
588 endElement(void *userData, const char *name)
589 {
590   //fprintf(stderr,"-tag: %s\n", name);
591   struct parsedata *pd = userData;
592   Pool *pool = pd->common.pool;
593   Solvable *s = pd->solvable;
594   Repo *repo = pd->common.repo;
595   Id id;
596
597   if (pd->depth != pd->statedepth)
598     {
599       pd->depth--;
600       // printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
601       return;
602     }
603   pd->depth--;
604   pd->statedepth--;
605   switch (pd->state)
606     {
607     case STATE_PATTERN:
608     case STATE_PRODUCT:
609     case STATE_SOLVABLE:
610       if (!s->arch)
611         s->arch = ARCH_NOARCH;
612       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
613         s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
614       s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
615       if (pd->numpacks > 0)
616         {
617           pd->numpacks--;
618           pd->solvable++;
619         }
620       pd->kind = 0;
621       break;
622     case STATE_NAME:
623       if ( pd->kind )
624           s->name = str2id(pool, join2( pd->kind, ":", pd->content), 1);
625       else
626           s->name = str2id(pool, pd->content, 1);
627       break;
628     case STATE_ARCH:
629       s->arch = str2id(pool, pd->content, 1);
630       break;
631     case STATE_VENDOR:
632       s->vendor = str2id(pool, pd->content, 1);
633       break;
634     case STATE_FILE:
635       id = str2id(pool, pd->content, 1);
636       s->provides = repo_addid(repo, s->provides, id);
637       break;
638     // xml store capabilities
639     case STATE_CAP_PROVIDES:
640       s->provides = adddepplain(pool, &pd->common, s->provides, pd->content, 0, pd->capkind);
641       break;
642     case STATE_CAP_REQUIRES:
643       s->requires = adddepplain(pool, &pd->common, s->requires, pd->content, 0, pd->capkind);
644       break;
645     case STATE_CAP_OBSOLETES:
646       s->obsoletes = adddepplain(pool, &pd->common, s->obsoletes, pd->content, 0, pd->capkind);
647       break;
648     case STATE_CAP_CONFLICTS:
649       s->conflicts = adddepplain(pool, &pd->common, s->conflicts, pd->content, 0, pd->capkind);
650       break;
651     case STATE_CAP_RECOMMENDS:
652       s->recommends = adddepplain(pool, &pd->common, s->recommends, pd->content, 0, pd->capkind);
653       break;
654     case STATE_CAP_SUPPLEMENTS:
655       s->supplements = adddepplain(pool, &pd->common, s->supplements, pd->content, 0, pd->capkind);
656       break;
657     case STATE_CAP_SUGGESTS:
658       s->suggests = adddepplain(pool, &pd->common, s->suggests, pd->content, 0, pd->capkind);
659       break;
660     case STATE_CAP_ENHANCES:
661       s->enhances = adddepplain(pool, &pd->common, s->enhances, pd->content, 0, pd->capkind);
662       break;
663     case STATE_CAP_FRESHENS:
664       s->freshens = adddepplain(pool, &pd->common, s->freshens, pd->content, 0, pd->capkind);
665       break;
666     case STATE_SUMMARY:
667       pd->lang = 0;
668       break;
669     case STATE_DESCRIPTION:
670       pd->lang = 0;
671       break;
672     case STATE_LOCATION:
673       repo_set_str(repo, s - pool->solvables, id_mediafile, pd->tmpattr);
674       break;
675     case STATE_CHECKSUM:
676       break;
677     default:
678       break;
679     }
680   pd->state = pd->sbtab[pd->state];
681   pd->docontent = 0;
682   //fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth);
683 }
684
685 static void XMLCALL
686 characterData(void *userData, const XML_Char *s, int len)
687 {
688   struct parsedata *pd = userData;
689   int l;
690   char *c;
691
692   if (!pd->docontent)
693     return;
694   l = pd->lcontent + len + 1;
695   if (l > pd->acontent)
696     {
697       pd->content = sat_realloc(pd->content, l + 256);
698       pd->acontent = l + 256;
699     }
700   c = pd->content + pd->lcontent;
701   pd->lcontent += len;
702   while (len-- > 0)
703     *c++ = *s++;
704   *c = 0;
705 }
706
707
708 #define BUFF_SIZE 8192
709
710 void
711 repo_add_rpmmd(Repo *repo, FILE *fp)
712 {
713   Pool *pool = repo->pool;
714   struct parsedata pd;
715   char buf[BUFF_SIZE];
716   int i, l;
717   struct stateswitch *sw;
718
719   memset(&pd, 0, sizeof(pd));
720   for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
721     {
722       if (!pd.swtab[sw->from])
723         pd.swtab[sw->from] = sw;
724       pd.sbtab[sw->to] = sw->from;
725     }
726   pd.common.pool = pool;
727   pd.common.repo = repo;
728
729   pd.data = repo_add_repodata(repo);
730   init_attr_ids(pool);
731
732   pd.content = sat_malloc(256);
733   pd.acontent = 256;
734   pd.lcontent = 0;
735   pd.common.tmp = 0;
736   pd.common.tmpl = 0;
737   pd.kind = 0;
738   XML_Parser parser = XML_ParserCreate(NULL);
739   XML_SetUserData(parser, &pd);
740   XML_SetElementHandler(parser, startElement, endElement);
741   XML_SetCharacterDataHandler(parser, characterData);
742   for (;;)
743     {
744       l = fread(buf, 1, sizeof(buf), fp);
745       if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
746         {
747           fprintf(stderr, "%s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
748           exit(1);
749         }
750       if (l == 0)
751         break;
752     }
753   XML_ParserFree(parser);
754
755   if (pd.data)
756     repodata_internalize(pd.data);
757
758   if (pd.numpacks)
759     repo_free_solvable_block(repo, pd.solvable - pool->solvables, pd.numpacks, 1);
760   sat_free(pd.content);
761 }