- add solv_strdup(), rename repo_freeallrepos() to pool_freeallrepos()
[platform/upstream/libsolv.git] / ext / repo_helix.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 /*
9  * repo_helix.c
10  * 
11  * Parse 'helix' XML representation
12  * and create 'repo'
13  * 
14  */
15
16 #include <sys/types.h>
17 #include <limits.h>
18 #include <fcntl.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <expat.h>
23
24 #include "repo_helix.h"
25 #include "evr.h"
26
27
28 /* XML parser states */
29
30 enum state {
31   STATE_START,
32   STATE_CHANNEL,
33   STATE_SUBCHANNEL,
34   STATE_PACKAGE,
35   STATE_NAME,
36   STATE_VENDOR,
37   STATE_BUILDTIME,
38   STATE_HISTORY,
39   STATE_UPDATE,
40   STATE_EPOCH,
41   STATE_VERSION,
42   STATE_RELEASE,
43   STATE_ARCH,
44   STATE_PROVIDES,
45   STATE_PROVIDESENTRY,
46   STATE_REQUIRES,
47   STATE_REQUIRESENTRY,
48   STATE_PREREQUIRES,
49   STATE_PREREQUIRESENTRY,
50   STATE_OBSOLETES,
51   STATE_OBSOLETESENTRY,
52   STATE_CONFLICTS,
53   STATE_CONFLICTSENTRY,
54   STATE_RECOMMENDS,
55   STATE_RECOMMENDSENTRY,
56   STATE_SUPPLEMENTS,
57   STATE_SUPPLEMENTSENTRY,
58   STATE_SUGGESTS,
59   STATE_SUGGESTSENTRY,
60   STATE_ENHANCES,
61   STATE_ENHANCESENTRY,
62   STATE_FRESHENS,
63   STATE_FRESHENSENTRY,
64
65   STATE_SELECTTION,
66   STATE_PATTERN,
67   STATE_ATOM,
68   STATE_PATCH,
69   STATE_PRODUCT,
70
71   STATE_PEPOCH,
72   STATE_PVERSION,
73   STATE_PRELEASE,
74   STATE_PARCH,
75
76   NUMSTATES
77 };
78
79 struct stateswitch {
80   enum state from;
81   char *ename;
82   enum state to;
83   int docontent;
84 };
85
86 static struct stateswitch stateswitches[] = {
87   { STATE_START,       "channel",         STATE_CHANNEL, 0 },
88   { STATE_CHANNEL,     "subchannel",      STATE_SUBCHANNEL, 0 },
89   { STATE_SUBCHANNEL,  "package",         STATE_PACKAGE, 0 },
90   { STATE_SUBCHANNEL,  "selection",       STATE_PACKAGE, 0 },
91   { STATE_SUBCHANNEL,  "pattern",         STATE_PACKAGE, 0 },
92   { STATE_SUBCHANNEL,  "atom",            STATE_PACKAGE, 0 },
93   { STATE_SUBCHANNEL,  "patch",           STATE_PACKAGE, 0 },
94   { STATE_SUBCHANNEL,  "product",         STATE_PACKAGE, 0 },
95   { STATE_PACKAGE,     "name",            STATE_NAME, 1 },
96   { STATE_PACKAGE,     "vendor",          STATE_VENDOR, 1 },
97   { STATE_PACKAGE,     "buildtime",       STATE_BUILDTIME, 1 },
98   { STATE_PACKAGE,     "epoch",           STATE_PEPOCH, 1 },
99   { STATE_PACKAGE,     "version",         STATE_PVERSION, 1 },
100   { STATE_PACKAGE,     "release",         STATE_PRELEASE, 1 },
101   { STATE_PACKAGE,     "arch",            STATE_PARCH, 1 },
102   { STATE_PACKAGE,     "history",         STATE_HISTORY, 0 },
103   { STATE_PACKAGE,     "provides",        STATE_PROVIDES, 0 },
104   { STATE_PACKAGE,     "requires",        STATE_REQUIRES, 0 },
105   { STATE_PACKAGE,     "prerequires",     STATE_PREREQUIRES, 0 },
106   { STATE_PACKAGE,     "obsoletes",       STATE_OBSOLETES , 0 },
107   { STATE_PACKAGE,     "conflicts",       STATE_CONFLICTS , 0 },
108   { STATE_PACKAGE,     "recommends" ,     STATE_RECOMMENDS , 0 },
109   { STATE_PACKAGE,     "supplements",     STATE_SUPPLEMENTS, 0 },
110   { STATE_PACKAGE,     "suggests",        STATE_SUGGESTS, 0 },
111   { STATE_PACKAGE,     "enhances",        STATE_ENHANCES, 0 },
112   { STATE_PACKAGE,     "freshens",        STATE_FRESHENS, 0 },
113
114   { STATE_HISTORY,     "update",          STATE_UPDATE, 0 },
115   { STATE_UPDATE,      "epoch",           STATE_EPOCH, 1 },
116   { STATE_UPDATE,      "version",         STATE_VERSION, 1 },
117   { STATE_UPDATE,      "release",         STATE_RELEASE, 1 },
118   { STATE_UPDATE,      "arch",            STATE_ARCH, 1 },
119
120   { STATE_PROVIDES,    "dep",             STATE_PROVIDESENTRY, 0 },
121   { STATE_REQUIRES,    "dep",             STATE_REQUIRESENTRY, 0 },
122   { STATE_PREREQUIRES, "dep",             STATE_PREREQUIRESENTRY, 0 },
123   { STATE_OBSOLETES,   "dep",             STATE_OBSOLETESENTRY, 0 },
124   { STATE_CONFLICTS,   "dep",             STATE_CONFLICTSENTRY, 0 },
125   { STATE_RECOMMENDS,  "dep",             STATE_RECOMMENDSENTRY, 0 },
126   { STATE_SUPPLEMENTS, "dep",             STATE_SUPPLEMENTSENTRY, 0 },
127   { STATE_SUGGESTS,    "dep",             STATE_SUGGESTSENTRY, 0 },
128   { STATE_ENHANCES,    "dep",             STATE_ENHANCESENTRY, 0 },
129   { STATE_FRESHENS,    "dep",             STATE_FRESHENSENTRY, 0 },
130   { NUMSTATES }
131
132 };
133
134 /*
135  * parser data
136  */
137
138 typedef struct _parsedata {
139   // XML parser data
140   int depth;
141   enum state state;     // current state
142   int statedepth;
143   char *content;        // buffer for content of node
144   int lcontent;         // actual length of current content
145   int acontent;         // actual buffer size
146   int docontent;        // handle content
147
148   // repo data
149   Pool *pool;           // current pool
150   Repo *repo;           // current repo
151   Repodata *data;       // current repo data
152   Solvable *solvable;   // current solvable
153   Offset freshens;      // current freshens vector
154
155   // package data
156   int  epoch;           // epoch (as offset into evrspace)
157   int  version;         // version (as offset into evrspace)
158   int  release;         // release (as offset into evrspace)
159   char *evrspace;       // buffer for evr
160   int  aevrspace;       // actual buffer space
161   int  levrspace;       // actual evr length
162   char *kind;
163
164   struct stateswitch *swtab[NUMSTATES];
165   enum state sbtab[NUMSTATES];
166 } Parsedata;
167
168
169 /*------------------------------------------------------------------*/
170 /* E:V-R handling */
171
172 // create Id from epoch:version-release
173
174 static Id
175 evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
176 {
177   char *c;
178   int l;
179
180   // treat explitcit 0 as NULL
181   if (e && !strcmp(e, "0"))
182     e = NULL;
183
184   if (v && !e)
185     {
186       const char *v2;
187       // scan version for ":"
188       for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)      // skip leading digits
189         ;
190       // if version contains ":", set epoch to "0"
191       if (v2 > v && *v2 == ':')
192         e = "0";
193     }
194   
195   // compute length of Id string
196   l = 1;  // for the \0
197   if (e)
198     l += strlen(e) + 1;  // e:
199   if (v)
200     l += strlen(v);      // v
201   if (r)
202     l += strlen(r) + 1;  // -r
203
204   // extend content if not sufficient
205   if (l > pd->acontent)
206     {
207       pd->content = (char *)realloc(pd->content, l + 256);
208       pd->acontent = l + 256;
209     }
210
211   // copy e-v-r to content
212   c = pd->content;
213   if (e)
214     {
215       strcpy(c, e);
216       c += strlen(c);
217       *c++ = ':';
218     }
219   if (v)
220     {
221       strcpy(c, v);
222       c += strlen(c);
223     }
224   if (r)
225     {
226       *c++ = '-';
227       strcpy(c, r);
228       c += strlen(c);
229     }
230   *c = 0;
231   // if nothing inserted, return Id 0
232   if (!*pd->content)
233     return ID_NULL;
234 #if 0
235   fprintf(stderr, "evr: %s\n", pd->content);
236 #endif
237   // intern and create
238   return pool_str2id(pool, pd->content, 1);
239 }
240
241
242 // create e:v-r from attributes
243 // atts is array of name,value pairs, NULL at end
244 //   even index into atts is name
245 //   odd index is value
246 //
247 static Id
248 evr_atts2id(Pool *pool, Parsedata *pd, const char **atts)
249 {
250   const char *e, *v, *r;
251   e = v = r = 0;
252   for (; *atts; atts += 2)
253     {
254       if (!strcmp(*atts, "epoch"))
255         e = atts[1];
256       else if (!strcmp(*atts, "version"))
257         v = atts[1];
258       else if (!strcmp(*atts, "release"))
259         r = atts[1];
260     }
261   return evr2id(pool, pd, e, v, r);
262 }
263
264 /*------------------------------------------------------------------*/
265 /* rel operator handling */
266
267 struct flagtab {
268   char *from;
269   int to;
270 };
271
272 static struct flagtab flagtab[] = {
273   { ">",  REL_GT },
274   { "=",  REL_EQ },
275   { ">=", REL_GT|REL_EQ },
276   { "<",  REL_LT },
277   { "!=", REL_GT|REL_LT },
278   { "<=", REL_LT|REL_EQ },
279   { "(any)", REL_LT|REL_EQ|REL_GT },
280   { "==", REL_EQ },
281   { "gt", REL_GT },
282   { "eq", REL_EQ },
283   { "ge", REL_GT|REL_EQ },
284   { "lt", REL_LT },
285   { "ne", REL_GT|REL_LT },
286   { "le", REL_LT|REL_EQ },
287   { "gte", REL_GT|REL_EQ },
288   { "lte", REL_LT|REL_EQ },
289   { "GT", REL_GT },
290   { "EQ", REL_EQ },
291   { "GE", REL_GT|REL_EQ },
292   { "LT", REL_LT },
293   { "NE", REL_GT|REL_LT },
294   { "LE", REL_LT|REL_EQ }
295 };
296
297 /*
298  * process new dependency from parser
299  *  olddeps = already collected deps, this defines the 'kind' of dep
300  *  atts = array of name,value attributes of dep
301  *  isreq == 1 if its a requires
302  */
303
304 static unsigned int
305 adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
306 {
307   Id id, name;
308   const char *n, *f, *k;
309   const char **a;
310
311   n = f = k = NULL;
312
313   /* loop over name,value pairs */
314   for (a = atts; *a; a += 2)
315     {
316       if (!strcmp(*a, "name"))
317         n = a[1];
318       if (!strcmp(*a, "kind"))
319         k = a[1];
320       else if (!strcmp(*a, "op"))
321         f = a[1];
322       else if (marker && !strcmp(*a, "pre") && a[1][0] == '1')
323         marker = SOLVABLE_PREREQMARKER;
324     }
325   if (!n)                              /* quit if no name found */
326     return olddeps;
327
328   /* kind, name */
329   if (k && !strcmp(k, "package"))
330     k = NULL;                          /* package is default */
331
332   if (k)                               /* if kind!=package, intern <kind>:<name> */
333     {
334       int l = strlen(k) + 1 + strlen(n) + 1;
335       if (l > pd->acontent)            /* extend buffer if needed */
336         {
337           pd->content = (char *)realloc(pd->content, l + 256);
338           pd->acontent = l + 256;
339         }
340       sprintf(pd->content, "%s:%s", k, n);
341       name = pool_str2id(pool, pd->content, 1);
342     }
343   else
344     {
345       name = pool_str2id(pool, n, 1);       /* package: just intern <name> */
346     }
347
348   if (f)                               /* operator ? */
349     {
350       /* intern e:v-r */
351       Id evr = evr_atts2id(pool, pd, atts);
352       /* parser operator to flags */
353       int flags;
354       for (flags = 0; flags < sizeof(flagtab)/sizeof(*flagtab); flags++)
355         if (!strcmp(f, flagtab[flags].from))
356           {
357             flags = flagtab[flags].to;
358             break;
359           }
360       if (flags > 7)
361         flags = 0;
362       /* intern rel */
363       id = pool_rel2id(pool, name, evr, flags, 1);
364     }
365   else
366     id = name;                         /* no operator */
367
368   /* add new dependency to repo */
369   return repo_addid_dep(pd->repo, olddeps, id, marker);
370 }
371
372
373 /*----------------------------------------------------------------*/
374
375 /*
376  * XML callback
377  * <name>
378  * 
379  */
380
381 static void XMLCALL
382 startElement(void *userData, const char *name, const char **atts)
383 {
384   Parsedata *pd = (Parsedata *)userData;
385   struct stateswitch *sw;
386   Pool *pool = pd->pool;
387   Solvable *s = pd->solvable;
388
389   if (pd->depth != pd->statedepth)
390     {
391       pd->depth++;
392       return;
393     }
394
395   /* ignore deps element */
396   if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
397     return;
398
399   pd->depth++;
400
401   /* find node name in stateswitch */
402   if (!pd->swtab[pd->state])
403     return;
404   for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
405   {
406     if (!strcmp(sw->ename, name))
407       break;
408   }
409
410   /* check if we're at the right level */
411   if (sw->from != pd->state)
412     {
413 #if 0
414       fprintf(stderr, "into unknown: %s\n", name);
415 #endif
416       return;
417     }
418   
419   // set new state
420   pd->state = sw->to;
421
422   pd->docontent = sw->docontent;
423   pd->statedepth = pd->depth;
424
425   // start with empty content
426   // (will collect data until end element
427   pd->lcontent = 0;
428   *pd->content = 0;
429
430   switch (pd->state)
431     {
432
433     case STATE_NAME:
434       if (pd->kind)                    /* if kind is set (non package) */
435         {
436           strcpy(pd->content, pd->kind);
437           pd->lcontent = strlen(pd->content);
438           pd->content[pd->lcontent++] = ':';   /* prefix name with '<kind>:' */
439           pd->content[pd->lcontent] = 0;
440         }
441       break;
442
443     case STATE_PACKAGE:                /* solvable name */
444       pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
445       if (!strcmp(name, "selection"))
446         pd->kind = "selection";
447       else if (!strcmp(name, "pattern"))
448         pd->kind = "pattern";
449       else if (!strcmp(name, "atom"))
450         pd->kind = "atom";
451       else if (!strcmp(name, "product"))
452         pd->kind = "product";
453       else if (!strcmp(name, "patch"))
454         pd->kind = "patch";
455       else
456         pd->kind = NULL;               /* default is package */
457       pd->levrspace = 1;
458       pd->epoch = 0;
459       pd->version = 0;
460       pd->release = 0;
461       pd->freshens = 0;
462 #if 0
463       fprintf(stderr, "package #%d\n", s - pool->solvables);
464 #endif
465       break;
466
467     case STATE_UPDATE:
468       pd->levrspace = 1;
469       pd->epoch = 0;
470       pd->version = 0;
471       pd->release = 0;
472       break;
473
474     case STATE_PROVIDES:               /* start of provides */
475       s->provides = 0;
476       break;
477     case STATE_PROVIDESENTRY:          /* entry within provides */
478       s->provides = adddep(pool, pd, s->provides, atts, 0);
479       break;
480     case STATE_REQUIRESENTRY:
481       s->requires = adddep(pool, pd, s->requires, atts, -SOLVABLE_PREREQMARKER);
482       break;
483     case STATE_PREREQUIRESENTRY:
484       s->requires = adddep(pool, pd, s->requires, atts, SOLVABLE_PREREQMARKER);
485       break;
486     case STATE_OBSOLETES:
487       s->obsoletes = 0;
488       break;
489     case STATE_OBSOLETESENTRY:
490       s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
491       break;
492     case STATE_CONFLICTS:
493       s->conflicts = 0;
494       break;
495     case STATE_CONFLICTSENTRY:
496       s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
497       break;
498     case STATE_RECOMMENDS:
499       s->recommends = 0;
500       break;
501     case STATE_RECOMMENDSENTRY:
502       s->recommends = adddep(pool, pd, s->recommends, atts, 0);
503       break;
504     case STATE_SUPPLEMENTS:
505       s->supplements= 0;
506       break;
507     case STATE_SUPPLEMENTSENTRY:
508       s->supplements = adddep(pool, pd, s->supplements, atts, 0);
509       break;
510     case STATE_SUGGESTS:
511       s->suggests = 0;
512       break;
513     case STATE_SUGGESTSENTRY:
514       s->suggests = adddep(pool, pd, s->suggests, atts, 0);
515       break;
516     case STATE_ENHANCES:
517       s->enhances = 0;
518       break;
519     case STATE_ENHANCESENTRY:
520       s->enhances = adddep(pool, pd, s->enhances, atts, 0);
521       break;
522     case STATE_FRESHENS:
523       pd->freshens = 0;
524       break;
525     case STATE_FRESHENSENTRY:
526       pd->freshens = adddep(pool, pd, pd->freshens, atts, 0);
527       break;
528     default:
529       break;
530     }
531 }
532
533 static const char *findKernelFlavor(Parsedata *pd, Solvable *s)
534 {
535   Pool *pool = pd->pool;
536   Id pid, *pidp;
537   
538   if (s->provides)
539     {
540       pidp = pd->repo->idarraydata + s->provides;
541       while ((pid = *pidp++) != 0)
542         {
543           Reldep *prd;
544           const char *depname;
545           
546           if (!ISRELDEP(pid))
547             continue;               /* wrong provides name */
548           prd = GETRELDEP(pool, pid);
549           depname = pool_id2str(pool, prd->name);
550           if (!strncmp(depname, "kernel-", 7))
551             return depname + 7;
552         }
553     }
554
555   if (s->requires)
556     {
557       pidp = pd->repo->idarraydata + s->requires;
558       while ((pid = *pidp++) != 0)
559         {
560           const char *depname;
561
562           if (!ISRELDEP(pid))
563             {
564               depname = pool_id2str(pool, pid);
565             } 
566           else 
567             {
568               Reldep *prd = GETRELDEP(pool, pid);
569               depname = pool_id2str(pool, prd->name);
570             }
571           if (!strncmp(depname, "kernel-", 7))
572             return depname + 7;
573         }
574     }
575
576   return 0;
577 }
578
579
580 /*
581  * XML callback
582  * </name>
583  * 
584  * create Solvable from collected data
585  */
586
587 static void XMLCALL
588 endElement(void *userData, const char *name)
589 {
590   Parsedata *pd = (Parsedata *)userData;
591   Pool *pool = pd->pool;
592   Solvable *s = pd->solvable;
593   Id evr;
594   unsigned int t = 0;
595
596   if (pd->depth != pd->statedepth)
597     {
598       pd->depth--;
599       // printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
600       return;
601     }
602
603   /* ignore deps element */
604   if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
605     return;
606
607   pd->depth--;
608   pd->statedepth--;
609   switch (pd->state)
610     {
611
612     case STATE_PACKAGE:                /* package complete */
613       if (!s->arch)                    /* default to "noarch" */
614         s->arch = ARCH_NOARCH;
615
616       if (!s->evr && pd->version)      /* set solvable evr */
617         s->evr = evr2id(pool, pd,
618                         pd->epoch   ? pd->evrspace + pd->epoch   : 0,
619                         pd->version ? pd->evrspace + pd->version : 0,
620                         pd->release ? pd->evrspace + pd->release : 0);
621       /* ensure self-provides */
622       if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
623         s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
624       s->supplements = repo_fix_supplements(pd->repo, s->provides, s->supplements, pd->freshens);
625       s->conflicts = repo_fix_conflicts(pd->repo, s->conflicts);
626       pd->freshens = 0;
627
628       /* see bugzilla bnc#190163 */
629       const char *flavor = findKernelFlavor(pd, s);
630       if (flavor) 
631         {
632           char *cflavor = solv_strdup(flavor);  /* make pointer safe */
633
634           Id npr;
635           Id pid;
636
637           /* this is either a kernel package or a kmp */
638           if (s->provides)
639             {
640               Offset prov = s->provides;
641               npr = 0;
642               while ((pid = pd->repo->idarraydata[prov++]) != 0)
643                 {
644                   const char *depname = 0;
645                   Reldep *prd = 0;
646
647                   if (ISRELDEP(pid))
648                     {
649                       prd = GETRELDEP(pool, pid);
650                       depname = pool_id2str(pool, prd->name);
651                     }
652                   else
653                     {
654                       depname = pool_id2str(pool, pid);
655                     }
656
657
658                   if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
659                     {
660                       char newdep[100];
661                       snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
662                       pid = pool_str2id(pool, newdep, 1);
663                       if (prd)
664                         pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
665                     }
666
667                   npr = repo_addid_dep(pd->repo, npr, pid, 0);
668                 }
669               s->provides = npr;
670             }
671 #if 1
672
673           if (s->requires)
674             {
675               Offset reqs = s->requires;
676               npr = 0;
677               while ((pid = pd->repo->idarraydata[reqs++]) != 0)
678                 {
679                   const char *depname = 0;
680                   Reldep *prd = 0;
681
682                   if (ISRELDEP(pid))
683                     {
684                       prd = GETRELDEP(pool, pid);
685                       depname = pool_id2str(pool, prd->name);
686                     }
687                   else
688                     {
689                       depname = pool_id2str(pool, pid);
690                     }
691
692                   if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
693                     {
694                       char newdep[100];
695                       snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
696                       pid = pool_str2id(pool, newdep, 1);
697                       if (prd)
698                         pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
699                     }
700                   npr = repo_addid_dep(pd->repo, npr, pid, 0);
701                 }
702               s->requires = npr;
703             }
704 #endif
705           free(cflavor);
706         }
707       break;
708     case STATE_NAME:
709       s->name = pool_str2id(pool, pd->content, 1);
710       break;
711     case STATE_VENDOR:
712       s->vendor = pool_str2id(pool, pd->content, 1);
713       break;
714     case STATE_BUILDTIME:
715       t = atoi (pd->content);
716       if (t)
717         repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
718       break;    
719     case STATE_UPDATE:                 /* new version, keeping all other metadata */
720       evr = evr2id(pool, pd,
721                    pd->epoch   ? pd->evrspace + pd->epoch   : 0,
722                    pd->version ? pd->evrspace + pd->version : 0,
723                    pd->release ? pd->evrspace + pd->release : 0);
724       pd->levrspace = 1;
725       pd->epoch = 0;
726       pd->version = 0;
727       pd->release = 0;
728       /* use highest evr */
729       if (!s->evr || pool_evrcmp(pool, s->evr, evr, EVRCMP_MATCH_RELEASE) <= 0)
730         s->evr = evr;
731       break;
732     case STATE_EPOCH:
733     case STATE_VERSION:
734     case STATE_RELEASE:
735     case STATE_PEPOCH:
736     case STATE_PVERSION:
737     case STATE_PRELEASE:
738       /* ensure buffer space */
739       if (pd->lcontent + 1 + pd->levrspace > pd->aevrspace)
740         {
741           pd->evrspace = (char *)realloc(pd->evrspace, pd->lcontent + 1 + pd->levrspace + 256);
742           pd->aevrspace = pd->lcontent + 1 + pd->levrspace + 256;
743         }
744       memcpy(pd->evrspace + pd->levrspace, pd->content, pd->lcontent + 1);
745       if (pd->state == STATE_EPOCH || pd->state == STATE_PEPOCH)
746         pd->epoch = pd->levrspace;
747       else if (pd->state == STATE_VERSION || pd->state == STATE_PVERSION)
748         pd->version = pd->levrspace;
749       else
750         pd->release = pd->levrspace;
751       pd->levrspace += pd->lcontent + 1;
752       break;
753     case STATE_ARCH:
754     case STATE_PARCH:
755       s->arch = pool_str2id(pool, pd->content, 1);
756       break;
757     default:
758       break;
759     }
760   pd->state = pd->sbtab[pd->state];
761   pd->docontent = 0;
762   // printf("back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth);
763 }
764
765
766 /*
767  * XML callback
768  * character data
769  * 
770  */
771
772 static void XMLCALL
773 characterData(void *userData, const XML_Char *s, int len)
774 {
775   Parsedata *pd = (Parsedata *)userData;
776   int l;
777   char *c;
778
779   // check if current nodes content is interesting
780   if (!pd->docontent)
781     return;
782
783   // adapt content buffer
784   l = pd->lcontent + len + 1;
785   if (l > pd->acontent)
786     {
787       pd->content = (char *)realloc(pd->content, l + 256);
788       pd->acontent = l + 256;
789     }
790   // append new content to buffer
791   c = pd->content + pd->lcontent;
792   pd->lcontent += len;
793   while (len-- > 0)
794     *c++ = *s++;
795   *c = 0;
796 }
797
798 /*-------------------------------------------------------------------*/
799
800 #define BUFF_SIZE 8192
801
802 /*
803  * read 'helix' type xml from fp
804  * add packages to pool/repo
805  * 
806  */
807
808 int
809 repo_add_helix(Repo *repo, FILE *fp, int flags)
810 {
811   Pool *pool = repo->pool;
812   Parsedata pd;
813   Repodata *data;
814   char buf[BUFF_SIZE];
815   int i, l;
816   struct stateswitch *sw;
817   unsigned int now;
818
819   now = solv_timems(0);
820   data = repo_add_repodata(repo, flags);
821   
822   /* prepare parsedata */
823   memset(&pd, 0, sizeof(pd));
824   for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
825     {
826       if (!pd.swtab[sw->from])
827         pd.swtab[sw->from] = sw;
828       pd.sbtab[sw->to] = sw->from;
829     }
830
831   pd.pool = pool;
832   pd.repo = repo;
833
834   pd.content = (char *)malloc(256);     /* must hold all solvable kinds! */
835   pd.acontent = 256;
836   pd.lcontent = 0;
837
838   pd.evrspace = (char *)malloc(256);
839   pd.aevrspace= 256;
840   pd.levrspace = 1;
841   pd.data = data;
842
843   // set up XML parser
844
845   XML_Parser parser = XML_ParserCreate(NULL);
846   XML_SetUserData(parser, &pd);       /* make parserdata available to XML callbacks */
847   XML_SetElementHandler(parser, startElement, endElement);
848   XML_SetCharacterDataHandler(parser, characterData);
849
850   // read/parse XML file
851   for (;;)
852     {
853       l = fread(buf, 1, sizeof(buf), fp);
854       if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
855         {
856           pool_debug(pool, SOLV_FATAL, "%s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
857           exit(1);
858         }
859       if (l == 0)
860         break;
861     }
862   XML_ParserFree(parser);
863   free(pd.content);
864   free(pd.evrspace);
865
866   if (!(flags & REPO_NO_INTERNALIZE))
867     repodata_internalize(data);
868   POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_helix took %d ms\n", solv_timems(now));
869   POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
870   POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data->incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
871   return 0;
872 }