Add rpm_data_t (and _constdata_t) for header data, use everywhere
[platform/upstream/rpm.git] / lib / rpmds.c
1 /** \ingroup rpmdep
2  * \file lib/rpmds.c
3  */
4 #include "system.h"
5
6 #include <rpm/rpmlib.h>
7 #include <rpm/rpmstring.h>
8 #include <rpm/rpmlog.h>
9
10 #include <rpm/rpmds.h>
11
12 #include "debug.h"
13
14 /**
15  * Enable noisy range comparison debugging message?
16  */
17 static int _noisy_range_comparison_debug_message = 0;
18
19 int _rpmds_debug = 0;
20
21 int _rpmds_nopromote = 1;
22
23 int _rpmds_unspecified_epoch_noise = 0;
24
25 /**
26  * A package dependency set.
27  */
28 struct rpmds_s {
29     const char * Type;          /*!< Tag name. */
30     char * DNEVR;               /*!< Formatted dependency string. */
31     Header h;                   /*!< Header for dependency set (or NULL) */
32     const char ** N;            /*!< Name. */
33     const char ** EVR;          /*!< Epoch-Version-Release. */
34     int32_t * Flags;            /*!< Bit(s) identifying context/comparison. */
35     uint32_t * Color;           /*!< Bit(s) calculated from file color(s). */
36     int32_t * Refs;             /*!< No. of file refs. */
37     int32_t BT;                 /*!< Package build time tie breaker. */
38     rpm_tag_t tagN;             /*!< Header tag. */
39     rpm_tagtype_t Nt, EVRt, Ft; /*!< Tag data types. */
40     int32_t Count;              /*!< No. of elements */
41     int i;                      /*!< Element index. */
42     unsigned l;                 /*!< Low element (bsearch). */
43     unsigned u;                 /*!< High element (bsearch). */
44     int nopromote;              /*!< Don't promote Epoch: in rpmdsCompare()? */
45     int nrefs;                  /*!< Reference count. */
46 };
47 rpmds rpmdsUnlink(rpmds ds, const char * msg)
48 {
49     if (ds == NULL) return NULL;
50 if (_rpmds_debug && msg != NULL)
51 fprintf(stderr, "--> ds %p -- %d %s\n", ds, ds->nrefs, msg);
52     ds->nrefs--;
53     return NULL;
54 }
55
56 rpmds rpmdsLink(rpmds ds, const char * msg)
57 {
58     if (ds == NULL) return NULL;
59     ds->nrefs++;
60
61 if (_rpmds_debug && msg != NULL)
62 fprintf(stderr, "--> ds %p ++ %d %s\n", ds, ds->nrefs, msg);
63
64     return ds;
65 }
66
67 rpmds rpmdsFree(rpmds ds)
68 {
69     HFD_t hfd = headerFreeData;
70     rpm_tag_t tagEVR, tagF;
71
72     if (ds == NULL)
73         return NULL;
74
75     if (ds->nrefs > 1)
76         return rpmdsUnlink(ds, ds->Type);
77
78 if (_rpmds_debug < 0)
79 fprintf(stderr, "*** ds %p\t%s[%d]\n", ds, ds->Type, ds->Count);
80
81     if (ds->tagN == RPMTAG_PROVIDENAME) {
82         tagEVR = RPMTAG_PROVIDEVERSION;
83         tagF = RPMTAG_PROVIDEFLAGS;
84     } else
85     if (ds->tagN == RPMTAG_REQUIRENAME) {
86         tagEVR = RPMTAG_REQUIREVERSION;
87         tagF = RPMTAG_REQUIREFLAGS;
88     } else
89     if (ds->tagN == RPMTAG_CONFLICTNAME) {
90         tagEVR = RPMTAG_CONFLICTVERSION;
91         tagF = RPMTAG_CONFLICTFLAGS;
92     } else
93     if (ds->tagN == RPMTAG_OBSOLETENAME) {
94         tagEVR = RPMTAG_OBSOLETEVERSION;
95         tagF = RPMTAG_OBSOLETEFLAGS;
96     } else
97     if (ds->tagN == RPMTAG_TRIGGERNAME) {
98         tagEVR = RPMTAG_TRIGGERVERSION;
99         tagF = RPMTAG_TRIGGERFLAGS;
100     } else
101         return NULL;
102
103     if (ds->Count > 0) {
104         ds->N = hfd(ds->N, ds->Nt);
105         ds->EVR = hfd(ds->EVR, ds->EVRt);
106         ds->Flags = (ds->h != NULL ? hfd(ds->Flags, ds->Ft) : _free(ds->Flags));
107         ds->h = headerFree(ds->h);
108     }
109
110     ds->DNEVR = _free(ds->DNEVR);
111     ds->Color = _free(ds->Color);
112     ds->Refs = _free(ds->Refs);
113
114     (void) rpmdsUnlink(ds, ds->Type);
115     memset(ds, 0, sizeof(*ds));         /* XXX trash and burn */
116     ds = _free(ds);
117     return NULL;
118 }
119
120 rpmds rpmdsNew(Header h, rpm_tag_t tagN, int flags)
121 {
122     int scareMem = (flags & 0x1);
123     HGE_t hge =
124         (scareMem ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry);
125     rpm_tag_t tagBT = RPMTAG_BUILDTIME;
126     rpm_tagtype_t BTt;
127     int32_t * BTp;
128     rpm_tag_t tagEVR, tagF;
129     rpmds ds = NULL;
130     const char * Type;
131     const char ** N;
132     rpm_tagtype_t Nt;
133     rpm_count_t Count;
134
135     if (tagN == RPMTAG_PROVIDENAME) {
136         Type = "Provides";
137         tagEVR = RPMTAG_PROVIDEVERSION;
138         tagF = RPMTAG_PROVIDEFLAGS;
139     } else
140     if (tagN == RPMTAG_REQUIRENAME) {
141         Type = "Requires";
142         tagEVR = RPMTAG_REQUIREVERSION;
143         tagF = RPMTAG_REQUIREFLAGS;
144     } else
145     if (tagN == RPMTAG_CONFLICTNAME) {
146         Type = "Conflicts";
147         tagEVR = RPMTAG_CONFLICTVERSION;
148         tagF = RPMTAG_CONFLICTFLAGS;
149     } else
150     if (tagN == RPMTAG_OBSOLETENAME) {
151         Type = "Obsoletes";
152         tagEVR = RPMTAG_OBSOLETEVERSION;
153         tagF = RPMTAG_OBSOLETEFLAGS;
154     } else
155     if (tagN == RPMTAG_TRIGGERNAME) {
156         Type = "Trigger";
157         tagEVR = RPMTAG_TRIGGERVERSION;
158         tagF = RPMTAG_TRIGGERFLAGS;
159     } else
160         goto exit;
161
162     if (hge(h, tagN, &Nt, (rpm_data_t *) &N, &Count)
163      && N != NULL && Count > 0)
164     {
165         int xx;
166
167         ds = xcalloc(1, sizeof(*ds));
168         ds->Type = Type;
169         ds->h = (scareMem ? headerLink(h) : NULL);
170         ds->i = -1;
171         ds->DNEVR = NULL;
172         ds->tagN = tagN;
173         ds->N = N;
174         ds->Nt = Nt;
175         ds->Count = Count;
176         ds->nopromote = _rpmds_nopromote;
177
178         xx = hge(h, tagEVR, &ds->EVRt, (rpm_data_t *) &ds->EVR, NULL);
179         xx = hge(h, tagF, &ds->Ft, (rpm_data_t *) &ds->Flags, NULL);
180         if (!scareMem && ds->Flags != NULL)
181             ds->Flags = memcpy(xmalloc(ds->Count * sizeof(*ds->Flags)),
182                                 ds->Flags, ds->Count * sizeof(*ds->Flags));
183         xx = hge(h, tagBT, &BTt, (rpm_data_t *) &BTp, NULL);
184         ds->BT = (xx && BTp != NULL && BTt == RPM_INT32_TYPE ? *BTp : 0);
185         ds->Color = xcalloc(Count, sizeof(*ds->Color));
186         ds->Refs = xcalloc(Count, sizeof(*ds->Refs));
187
188 if (_rpmds_debug < 0)
189 fprintf(stderr, "*** ds %p\t%s[%d]\n", ds, ds->Type, ds->Count);
190
191     }
192
193 exit:
194     /* FIX: ds->Flags may be NULL */
195     ds = rpmdsLink(ds, (ds ? ds->Type : RPMDBG()));
196
197     return ds;
198 }
199
200 char * rpmdsNewDNEVR(const char * dspfx, const rpmds ds)
201 {
202     char * tbuf, * t;
203     size_t nb;
204
205     nb = 0;
206     if (dspfx)  nb += strlen(dspfx) + 1;
207     if (ds->N[ds->i])   nb += strlen(ds->N[ds->i]);
208     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
209     if (ds->Flags != NULL && (ds->Flags[ds->i] & RPMSENSE_SENSEMASK)) {
210         if (nb) nb++;
211         if (ds->Flags[ds->i] & RPMSENSE_LESS)   nb++;
212         if (ds->Flags[ds->i] & RPMSENSE_GREATER) nb++;
213         if (ds->Flags[ds->i] & RPMSENSE_EQUAL)  nb++;
214     }
215     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
216     if (ds->EVR != NULL && ds->EVR[ds->i] && *ds->EVR[ds->i]) {
217         if (nb) nb++;
218         nb += strlen(ds->EVR[ds->i]);
219     }
220
221     t = tbuf = xmalloc(nb + 1);
222     if (dspfx) {
223         t = stpcpy(t, dspfx);
224         *t++ = ' ';
225     }
226     if (ds->N[ds->i])
227         t = stpcpy(t, ds->N[ds->i]);
228     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
229     if (ds->Flags != NULL && (ds->Flags[ds->i] & RPMSENSE_SENSEMASK)) {
230         if (t != tbuf)  *t++ = ' ';
231         if (ds->Flags[ds->i] & RPMSENSE_LESS)   *t++ = '<';
232         if (ds->Flags[ds->i] & RPMSENSE_GREATER) *t++ = '>';
233         if (ds->Flags[ds->i] & RPMSENSE_EQUAL)  *t++ = '=';
234     }
235     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
236     if (ds->EVR != NULL && ds->EVR[ds->i] && *ds->EVR[ds->i]) {
237         if (t != tbuf)  *t++ = ' ';
238         t = stpcpy(t, ds->EVR[ds->i]);
239     }
240     *t = '\0';
241     return tbuf;
242 }
243
244 rpmds rpmdsThis(Header h, rpm_tag_t tagN, int32_t Flags)
245 {
246     HGE_t hge = (HGE_t) headerGetEntryMinMemory;
247     rpmds ds = NULL;
248     const char * Type;
249     const char * n, * v, * r;
250     int32_t * ep;
251     const char ** N, ** EVR;
252     char * t;
253     int xx;
254
255     if (tagN == RPMTAG_PROVIDENAME) {
256         Type = "Provides";
257     } else
258     if (tagN == RPMTAG_REQUIRENAME) {
259         Type = "Requires";
260     } else
261     if (tagN == RPMTAG_CONFLICTNAME) {
262         Type = "Conflicts";
263     } else
264     if (tagN == RPMTAG_OBSOLETENAME) {
265         Type = "Obsoletes";
266     } else
267     if (tagN == RPMTAG_TRIGGERNAME) {
268         Type = "Trigger";
269     } else
270         goto exit;
271
272     xx = headerNVR(h, &n, &v, &r);
273     ep = NULL;
274     xx = hge(h, RPMTAG_EPOCH, NULL, (rpm_data_t *)&ep, NULL);
275
276     t = xmalloc(sizeof(*N) + strlen(n) + 1);
277     N = (const char **) t;
278     t += sizeof(*N);
279     *t = '\0';
280     N[0] = t;
281     t = stpcpy(t, n);
282
283     t = xmalloc(sizeof(*EVR) +
284                 (ep ? 20 : 0) + strlen(v) + strlen(r) + sizeof("-"));
285     EVR = (const char **) t;
286     t += sizeof(*EVR);
287     *t = '\0';
288     EVR[0] = t;
289     if (ep) {
290         sprintf(t, "%d:", *ep);
291         t += strlen(t);
292     }
293     t = stpcpy( stpcpy( stpcpy( t, v), "-"), r);
294
295     ds = xcalloc(1, sizeof(*ds));
296     ds->h = NULL;
297     ds->Type = Type;
298     ds->tagN = tagN;
299     ds->Count = 1;
300     ds->N = N;
301     ds->Nt = RPM_FORCEFREE_TYPE;        /* XXX to insure that hfd will free */
302     ds->EVR = EVR;
303     ds->EVRt = RPM_FORCEFREE_TYPE;      /* XXX to insure that hfd will free */
304     ds->Flags = xmalloc(sizeof(*ds->Flags));    ds->Flags[0] = Flags;
305     ds->i = 0;
306     {   char pre[2];
307         pre[0] = ds->Type[0];
308         pre[1] = '\0';
309         /* LCL: ds->Type may be NULL ??? */
310         ds->DNEVR = rpmdsNewDNEVR(pre, ds);
311     }
312
313 exit:
314     return rpmdsLink(ds, (ds ? ds->Type : RPMDBG()));
315 }
316
317 rpmds rpmdsSingle(rpm_tag_t tagN, const char * N, const char * EVR, int32_t Flags)
318 {
319     rpmds ds = NULL;
320     const char * Type;
321
322     if (tagN == RPMTAG_PROVIDENAME) {
323         Type = "Provides";
324     } else
325     if (tagN == RPMTAG_REQUIRENAME) {
326         Type = "Requires";
327     } else
328     if (tagN == RPMTAG_CONFLICTNAME) {
329         Type = "Conflicts";
330     } else
331     if (tagN == RPMTAG_OBSOLETENAME) {
332         Type = "Obsoletes";
333     } else
334     if (tagN == RPMTAG_TRIGGERNAME) {
335         Type = "Trigger";
336     } else
337         goto exit;
338
339     ds = xcalloc(1, sizeof(*ds));
340     ds->h = NULL;
341     ds->Type = Type;
342     ds->tagN = tagN;
343     {   time_t now = time(NULL);
344         ds->BT = now;
345     }
346     ds->Count = 1;
347     ds->N = xmalloc(sizeof(*ds->N));            ds->N[0] = N;
348     ds->Nt = RPM_FORCEFREE_TYPE;        /* XXX to insure that hfd will free */
349     ds->EVR = xmalloc(sizeof(*ds->EVR));        ds->EVR[0] = EVR;
350     ds->EVRt = RPM_FORCEFREE_TYPE;      /* XXX to insure that hfd will free */
351     ds->Flags = xmalloc(sizeof(*ds->Flags));    ds->Flags[0] = Flags;
352     ds->i = 0;
353     {   char t[2];
354         t[0] = ds->Type[0];
355         t[1] = '\0';
356         ds->DNEVR = rpmdsNewDNEVR(t, ds);
357     }
358
359 exit:
360     return rpmdsLink(ds, (ds ? ds->Type : NULL));
361 }
362
363 int rpmdsCount(const rpmds ds)
364 {
365     return (ds != NULL ? ds->Count : 0);
366 }
367
368 int rpmdsIx(const rpmds ds)
369 {
370     return (ds != NULL ? ds->i : -1);
371 }
372
373 int rpmdsSetIx(rpmds ds, int ix)
374 {
375     int i = -1;
376
377     if (ds != NULL) {
378         i = ds->i;
379         ds->i = ix;
380     }
381     return i;
382 }
383
384 const char * rpmdsDNEVR(const rpmds ds)
385 {
386     const char * DNEVR = NULL;
387
388     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
389         if (ds->DNEVR != NULL)
390             DNEVR = ds->DNEVR;
391     }
392     return DNEVR;
393 }
394
395 const char * rpmdsN(const rpmds ds)
396 {
397     const char * N = NULL;
398
399     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
400         if (ds->N != NULL)
401             N = ds->N[ds->i];
402     }
403     return N;
404 }
405
406 const char * rpmdsEVR(const rpmds ds)
407 {
408     const char * EVR = NULL;
409
410     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
411         if (ds->EVR != NULL)
412             EVR = ds->EVR[ds->i];
413     }
414     return EVR;
415 }
416
417 int32_t rpmdsFlags(const rpmds ds)
418 {
419     int32_t Flags = 0;
420
421     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
422         if (ds->Flags != NULL)
423             Flags = ds->Flags[ds->i];
424     }
425     return Flags;
426 }
427
428 rpm_tag_t rpmdsTagN(const rpmds ds)
429 {
430     rpm_tag_t tagN = 0;
431
432     if (ds != NULL)
433         tagN = ds->tagN;
434     return tagN;
435 }
436
437 time_t rpmdsBT(const rpmds ds)
438 {
439     time_t BT = 0;
440     if (ds != NULL && ds->BT > 0)
441         BT = ds->BT;
442     return BT;
443 }
444
445 time_t rpmdsSetBT(const rpmds ds, time_t BT)
446 {
447     time_t oBT = 0;
448     if (ds != NULL) {
449         oBT = ds->BT;
450         ds->BT = BT;
451     }
452     return oBT;
453 }
454
455 int rpmdsNoPromote(const rpmds ds)
456 {
457     int nopromote = 0;
458
459     if (ds != NULL)
460         nopromote = ds->nopromote;
461     return nopromote;
462 }
463
464 int rpmdsSetNoPromote(rpmds ds, int nopromote)
465 {
466     int onopromote = 0;
467
468     if (ds != NULL) {
469         onopromote = ds->nopromote;
470         ds->nopromote = nopromote;
471     }
472     return onopromote;
473 }
474
475 uint32_t rpmdsColor(const rpmds ds)
476 {
477     uint32_t Color = 0;
478
479     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
480         if (ds->Color != NULL)
481             Color = ds->Color[ds->i];
482     }
483     return Color;
484 }
485
486 uint32_t rpmdsSetColor(const rpmds ds, uint32_t color)
487 {
488     uint32_t ocolor = 0;
489
490     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
491         if (ds->Color != NULL) {
492             ocolor = ds->Color[ds->i];
493             ds->Color[ds->i] = color;
494         }
495     }
496     return ocolor;
497 }
498
499 int32_t rpmdsRefs(const rpmds ds)
500 {
501     int32_t Refs = 0;
502
503     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
504         if (ds->Refs != NULL)
505             Refs = ds->Refs[ds->i];
506     }
507     return Refs;
508 }
509
510 int32_t rpmdsSetRefs(const rpmds ds, int32_t refs)
511 {
512     int32_t orefs = 0;
513
514     if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
515         if (ds->Refs != NULL) {
516             orefs = ds->Refs[ds->i];
517             ds->Refs[ds->i] = refs;
518         }
519     }
520     return orefs;
521 }
522
523 void rpmdsNotify(rpmds ds, const char * where, int rc)
524 {
525     if (!(ds != NULL && ds->i >= 0 && ds->i < ds->Count))
526         return;
527     if (!(ds->Type != NULL && ds->DNEVR != NULL))
528         return;
529
530     rpmlog(RPMLOG_DEBUG, "%9s: %-45s %-s %s\n", ds->Type,
531                 (!strcmp(ds->DNEVR, "cached") ? ds->DNEVR : ds->DNEVR+2),
532                 (rc ? _("NO ") : _("YES")),
533                 (where != NULL ? where : ""));
534 }
535
536 int rpmdsNext(rpmds ds)
537 {
538     int i = -1;
539
540     if (ds != NULL && ++ds->i >= 0) {
541         if (ds->i < ds->Count) {
542             char t[2];
543             i = ds->i;
544             ds->DNEVR = _free(ds->DNEVR);
545             t[0] = ((ds->Type != NULL) ? ds->Type[0] : '\0');
546             t[1] = '\0';
547             ds->DNEVR = rpmdsNewDNEVR(t, ds);
548
549         } else
550             ds->i = -1;
551
552 if (_rpmds_debug  < 0 && i != -1)
553 fprintf(stderr, "*** ds %p\t%s[%d]: %s\n", ds, (ds->Type ? ds->Type : "?Type?"), i, (ds->DNEVR ? ds->DNEVR : "?DNEVR?"));
554
555     }
556
557     return i;
558 }
559
560 rpmds rpmdsInit(rpmds ds)
561 {
562     if (ds != NULL)
563         ds->i = -1;
564     return ds;
565 }
566
567 static
568 const char ** rpmdsDupArgv(const char ** argv, int argc)
569 {
570     const char ** av;
571     size_t nb = 0;
572     int ac = 0;
573     char * t;
574
575     if (argv == NULL)
576         return NULL;
577     for (ac = 0; ac < argc; ac++) {
578 assert(argv[ac] != NULL);
579         nb += strlen(argv[ac]) + 1;
580     }
581     nb += (ac + 1) * sizeof(*av);
582
583     av = xmalloc(nb);
584     t = (char *) (av + ac + 1);
585     for (ac = 0; ac < argc; ac++) {
586         av[ac] = t;
587         t = stpcpy(t, argv[ac]) + 1;
588     }
589     av[ac] = NULL;
590     return av;
591 }
592
593 static rpmds rpmdsDup(const rpmds ods)
594 {
595     rpmds ds = xcalloc(1, sizeof(*ds));
596     size_t nb;
597
598     ds->h = (ods->h != NULL ? headerLink(ods->h) : NULL);
599     ds->Type = ods->Type;
600     ds->tagN = ods->tagN;
601     ds->Count = ods->Count;
602     ds->i = ods->i;
603     ds->l = ods->l;
604     ds->u = ods->u;
605
606     nb = (ds->Count+1) * sizeof(*ds->N);
607     ds->N = (ds->h != NULL
608         ? memcpy(xmalloc(nb), ods->N, nb)
609         : rpmdsDupArgv(ods->N, ods->Count) );
610     ds->Nt = ods->Nt;
611
612     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
613 assert(ods->EVR != NULL);
614 assert(ods->Flags != NULL);
615
616     nb = (ds->Count+1) * sizeof(*ds->EVR);
617     ds->EVR = (ds->h != NULL
618         ? memcpy(xmalloc(nb), ods->EVR, nb)
619         : rpmdsDupArgv(ods->EVR, ods->Count) );
620     ds->EVRt = ods->EVRt;
621
622     nb = (ds->Count * sizeof(*ds->Flags));
623     ds->Flags = (ds->h != NULL
624         ? ods->Flags
625         : memcpy(xmalloc(nb), ods->Flags, nb) );
626     ds->Ft = ods->Ft;
627
628 /* FIX: ds->Flags is kept, not only */
629     return rpmdsLink(ds, (ds ? ds->Type : NULL));
630
631 }
632
633 int rpmdsFind(rpmds ds, const rpmds ods)
634 {
635     int comparison;
636
637     if (ds == NULL || ods == NULL)
638         return -1;
639
640     ds->l = 0;
641     ds->u = ds->Count;
642     while (ds->l < ds->u) {
643         ds->i = (ds->l + ds->u) / 2;
644
645         comparison = strcmp(ods->N[ods->i], ds->N[ds->i]);
646
647         /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
648         if (comparison == 0 && ods->EVR && ds->EVR)
649             comparison = strcmp(ods->EVR[ods->i], ds->EVR[ds->i]);
650         if (comparison == 0 && ods->Flags && ds->Flags)
651             comparison = (ods->Flags[ods->i] - ds->Flags[ds->i]);
652
653         if (comparison < 0)
654             ds->u = ds->i;
655         else if (comparison > 0)
656             ds->l = ds->i + 1;
657         else
658             return ds->i;
659     }
660     return -1;
661 }
662
663 int rpmdsMerge(rpmds * dsp, rpmds ods)
664 {
665     rpmds ds;
666     const char ** N;
667     const char ** EVR;
668     int32_t * Flags;
669     int j;
670 int save;
671
672     if (dsp == NULL || ods == NULL)
673         return -1;
674
675     /* If not initialized yet, dup the 1st entry. */
676     if (*dsp == NULL) {
677         save = ods->Count;
678         ods->Count = 1;
679         *dsp = rpmdsDup(ods);
680         ods->Count = save;
681     }
682     ds = *dsp;
683     if (ds == NULL)
684         return -1;
685
686     /*
687      * Add new entries.
688      */
689 save = ods->i;
690     ods = rpmdsInit(ods);
691     if (ods != NULL)
692     while (rpmdsNext(ods) >= 0) {
693         /*
694          * If this entry is already present, don't bother.
695          */
696         if (rpmdsFind(ds, ods) >= 0)
697             continue;
698
699         /*
700          * Insert new entry.
701          */
702         for (j = ds->Count; j > ds->u; j--)
703             ds->N[j] = ds->N[j-1];
704         ds->N[ds->u] = ods->N[ods->i];
705         N = rpmdsDupArgv(ds->N, ds->Count+1);
706         ds->N = _free(ds->N);
707         ds->N = N;
708         
709         /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
710 assert(ods->EVR != NULL);
711 assert(ods->Flags != NULL);
712
713         for (j = ds->Count; j > ds->u; j--)
714             ds->EVR[j] = ds->EVR[j-1];
715         ds->EVR[ds->u] = ods->EVR[ods->i];
716         EVR = rpmdsDupArgv(ds->EVR, ds->Count+1);
717         ds->EVR = _free(ds->EVR);
718         ds->EVR = EVR;
719
720         Flags = xmalloc((ds->Count+1) * sizeof(*Flags));
721         if (ds->u > 0)
722             memcpy(Flags, ds->Flags, ds->u * sizeof(*Flags));
723         if (ds->u < ds->Count)
724             memcpy(Flags + ds->u + 1, ds->Flags + ds->u, (ds->Count - ds->u) * sizeof(*Flags));
725         Flags[ds->u] = ods->Flags[ods->i];
726         ds->Flags = _free(ds->Flags);
727         ds->Flags = Flags;
728
729         ds->i = ds->Count;
730         ds->Count++;
731
732     }
733 ods->i = save;
734     return 0;
735 }
736
737 /**
738  * Split EVR into epoch, version, and release components.
739  * @param evr           [epoch:]version[-release] string
740  * @retval *ep          pointer to epoch
741  * @retval *vp          pointer to version
742  * @retval *rp          pointer to release
743  */
744 static
745 void parseEVR(char * evr,
746                 const char ** ep,
747                 const char ** vp,
748                 const char ** rp)
749 {
750     const char *epoch;
751     const char *version;                /* assume only version is present */
752     const char *release;
753     char *s, *se;
754
755     s = evr;
756     while (*s && xisdigit(*s)) s++;     /* s points to epoch terminator */
757     se = strrchr(s, '-');               /* se points to version terminator */
758
759     if (*s == ':') {
760         epoch = evr;
761         *s++ = '\0';
762         version = s;
763         if (*epoch == '\0') epoch = "0";
764     } else {
765         epoch = NULL;   /* XXX disable epoch compare if missing */
766         version = evr;
767     }
768     if (se) {
769         *se++ = '\0';
770         release = se;
771     } else {
772         release = NULL;
773     }
774
775     if (ep) *ep = epoch;
776     if (vp) *vp = version;
777     if (rp) *rp = release;
778 }
779
780 int rpmdsCompare(const rpmds A, const rpmds B)
781 {
782     char *aDepend = (A->DNEVR != NULL ? xstrdup(A->DNEVR+2) : "");
783     char *bDepend = (B->DNEVR != NULL ? xstrdup(B->DNEVR+2) : "");
784     char *aEVR, *bEVR;
785     const char *aE, *aV, *aR, *bE, *bV, *bR;
786     int result;
787     int sense;
788
789     /* Different names don't overlap. */
790     if (strcmp(A->N[A->i], B->N[B->i])) {
791         result = 0;
792         goto exit;
793     }
794
795     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
796     if (!(A->EVR && A->Flags && B->EVR && B->Flags)) {
797         result = 1;
798         goto exit;
799     }
800
801     /* Same name. If either A or B is an existence test, always overlap. */
802     if (!((A->Flags[A->i] & RPMSENSE_SENSEMASK) && (B->Flags[B->i] & RPMSENSE_SENSEMASK))) {
803         result = 1;
804         goto exit;
805     }
806
807     /* If either EVR is non-existent or empty, always overlap. */
808     if (!(A->EVR[A->i] && *A->EVR[A->i] && B->EVR[B->i] && *B->EVR[B->i])) {
809         result = 1;
810         goto exit;
811     }
812
813     /* Both AEVR and BEVR exist. */
814     aEVR = xstrdup(A->EVR[A->i]);
815     parseEVR(aEVR, &aE, &aV, &aR);
816     bEVR = xstrdup(B->EVR[B->i]);
817     parseEVR(bEVR, &bE, &bV, &bR);
818
819     /* Compare {A,B} [epoch:]version[-release] */
820     sense = 0;
821     if (aE && *aE && bE && *bE)
822         sense = rpmvercmp(aE, bE);
823     else if (aE && *aE && atol(aE) > 0) {
824         if (!B->nopromote) {
825             int lvl = (_rpmds_unspecified_epoch_noise  ? RPMLOG_WARNING : RPMLOG_DEBUG);
826             rpmlog(lvl, _("The \"B\" dependency needs an epoch (assuming same epoch as \"A\")\n\tA = \"%s\"\tB = \"%s\"\n"),
827                 aDepend, bDepend);
828             sense = 0;
829         } else
830             sense = 1;
831     } else if (bE && *bE && atol(bE) > 0)
832         sense = -1;
833
834     if (sense == 0) {
835         sense = rpmvercmp(aV, bV);
836         if (sense == 0 && aR && *aR && bR && *bR)
837             sense = rpmvercmp(aR, bR);
838     }
839     aEVR = _free(aEVR);
840     bEVR = _free(bEVR);
841
842     /* Detect overlap of {A,B} range. */
843     result = 0;
844     if (sense < 0 && ((A->Flags[A->i] & RPMSENSE_GREATER) || (B->Flags[B->i] & RPMSENSE_LESS))) {
845         result = 1;
846     } else if (sense > 0 && ((A->Flags[A->i] & RPMSENSE_LESS) || (B->Flags[B->i] & RPMSENSE_GREATER))) {
847         result = 1;
848     } else if (sense == 0 &&
849         (((A->Flags[A->i] & RPMSENSE_EQUAL) && (B->Flags[B->i] & RPMSENSE_EQUAL)) ||
850          ((A->Flags[A->i] & RPMSENSE_LESS) && (B->Flags[B->i] & RPMSENSE_LESS)) ||
851          ((A->Flags[A->i] & RPMSENSE_GREATER) && (B->Flags[B->i] & RPMSENSE_GREATER)))) {
852         result = 1;
853     }
854
855 exit:
856     if (_noisy_range_comparison_debug_message)
857     rpmlog(RPMLOG_DEBUG, _("  %s    A %s\tB %s\n"),
858         (result ? _("YES") : _("NO ")), aDepend, bDepend);
859     aDepend = _free(aDepend);
860     bDepend = _free(bDepend);
861     return result;
862 }
863
864 void rpmdsProblem(rpmps ps, const char * pkgNEVR, const rpmds ds,
865         const fnpyKey * suggestedKeys, int adding)
866 {
867     const char * Name =  rpmdsN(ds);
868     const char * DNEVR = rpmdsDNEVR(ds);
869     const char * EVR = rpmdsEVR(ds);
870     rpmProblemType type;
871     fnpyKey key;
872
873     if (ps == NULL) return;
874
875     if (Name == NULL) Name = "?N?";
876     if (EVR == NULL) EVR = "?EVR?";
877     if (DNEVR == NULL) DNEVR = "? ?N? ?OP? ?EVR?";
878
879     rpmlog(RPMLOG_DEBUG, _("package %s has unsatisfied %s: %s\n"),
880             pkgNEVR, ds->Type, DNEVR+2);
881
882     switch ((unsigned)DNEVR[0]) {
883     case 'C':   type = RPMPROB_CONFLICT;        break;
884     default:
885     case 'R':   type = RPMPROB_REQUIRES;        break;
886     }
887
888     key = (suggestedKeys ? suggestedKeys[0] : NULL);
889     rpmpsAppend(ps, type, pkgNEVR, key, NULL, NULL, DNEVR, adding);
890 }
891
892 int rpmdsAnyMatchesDep (const Header h, const rpmds req, int nopromote)
893 {
894     int scareMem = 0;
895     rpmds provides = NULL;
896     int result = 0;
897
898     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
899     if (req->EVR == NULL || req->Flags == NULL)
900         return 1;
901
902     if (!(req->Flags[req->i] & RPMSENSE_SENSEMASK) || !req->EVR[req->i] || *req->EVR[req->i] == '\0')
903         return 1;
904
905     /* Get provides information from header */
906     provides = rpmdsInit(rpmdsNew(h, RPMTAG_PROVIDENAME, scareMem));
907     if (provides == NULL)
908         goto exit;      /* XXX should never happen */
909     if (nopromote)
910         (void) rpmdsSetNoPromote(provides, nopromote);
911
912     /*
913      * Rpm prior to 3.0.3 did not have versioned provides.
914      * If no provides version info is available, match any/all requires
915      * with same name.
916      */
917     if (provides->EVR == NULL) {
918         result = 1;
919         goto exit;
920     }
921
922     result = 0;
923     if (provides != NULL)
924     while (rpmdsNext(provides) >= 0) {
925
926         /* Filter out provides that came along for the ride. */
927         if (strcmp(provides->N[provides->i], req->N[req->i]))
928             continue;
929
930         result = rpmdsCompare(provides, req);
931
932         /* If this provide matches the require, we're done. */
933         if (result)
934             break;
935     }
936
937 exit:
938     provides = rpmdsFree(provides);
939
940     return result;
941 }
942
943 int rpmdsNVRMatchesDep(const Header h, const rpmds req, int nopromote)
944 {
945     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
946     const char * pkgN, * v, * r;
947     int32_t * epoch;
948     const char * pkgEVR;
949     char * t;
950     int32_t pkgFlags = RPMSENSE_EQUAL;
951     rpmds pkg;
952     int rc = 1; /* XXX assume match, names already match here */
953
954     /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
955     if (req->EVR == NULL || req->Flags == NULL)
956         return rc;
957
958     if (!((req->Flags[req->i] & RPMSENSE_SENSEMASK) && req->EVR[req->i] && *req->EVR[req->i]))
959         return rc;
960
961     /* Get package information from header */
962     (void) headerNVR(h, &pkgN, &v, &r);
963
964     t = alloca(21 + strlen(v) + 1 + strlen(r) + 1);
965     pkgEVR = t;
966     *t = '\0';
967     if (hge(h, RPMTAG_EPOCH, NULL, (rpm_data_t *) &epoch, NULL)) {
968         sprintf(t, "%d:", *epoch);
969         while (*t != '\0')
970             t++;
971     }
972     (void) stpcpy( stpcpy( stpcpy(t, v) , "-") , r);
973
974     if ((pkg = rpmdsSingle(RPMTAG_PROVIDENAME, pkgN, pkgEVR, pkgFlags)) != NULL) {
975         if (nopromote)
976             (void) rpmdsSetNoPromote(pkg, nopromote);
977         rc = rpmdsCompare(pkg, req);
978         pkg = rpmdsFree(pkg);
979     }
980
981     return rc;
982 }