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