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