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