Replace bunch of rpm version checks with feature checks to get this to
[apt.git] / apt-pkg / rpm / rpmversion.cc
1 // -*- mode: c++; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: rpmversion.cc,v 1.4 2002/11/19 13:03:29 niemeyer Exp $
4 /* ######################################################################
5
6    RPM Version - Versioning system for RPM
7
8    This implements the standard RPM versioning system.
9    
10    ##################################################################### 
11  */
12                                                                         /*}}}*/
13 // Include Files                                                        /*{{{*/
14 #ifdef __GNUG__
15 #pragma implementation "apt-pkg/rpmversion.h"
16 #endif
17
18 #include <config.h>
19
20 #ifdef HAVE_RPM
21
22 #include <apt-pkg/rpmversion.h>
23 #include <apt-pkg/pkgcache.h>
24
25 #include <rpm/rpmlib.h>
26 #if HAVE_RPM_MISC_H
27 #include <rpm/misc.h>
28 #endif
29
30 #include <stdlib.h>
31 #include <assert.h>
32
33 #if RPM_VERSION >= 0x040100
34 #include <rpm/rpmds.h>
35 #endif
36
37 rpmVersioningSystem rpmVS;
38
39 // rpmVS::rpmVersioningSystem - Constructor                             /*{{{*/
40 // ---------------------------------------------------------------------
41 /* */
42 rpmVersioningSystem::rpmVersioningSystem()
43 {
44    Label = "Standard .rpm";
45 }
46                                                                         /*}}}*/
47 // rpmVS::ParseVersion - Parse a version into it's components           /*{{{*/
48 // ---------------------------------------------------------------------
49 /* Code ripped from rpmlib */
50 void rpmVersioningSystem::ParseVersion(const char *V, const char *VEnd,
51                                        char **Epoch, 
52                                        char **Version,
53                                        char **Release)
54 {
55    string tmp = string(V, VEnd);
56    char *evr = strdup(tmp.c_str());
57    const char *epoch = NULL;
58    const char *version = NULL;
59    const char *release = NULL;
60    char *s;
61
62    assert(evr != NULL);
63    
64    s = strrchr(evr, '-');
65    if (s) {
66       *s++ = '\0';
67       release = s;
68    }
69    s = evr;
70    while (isdigit(*s)) s++;
71    if (*s == ':')
72    {
73       epoch = evr;
74       *s++ = '\0';
75       version = s;
76       if (*epoch == '\0') epoch = "0";
77    }
78    else
79    {
80 #if RPM_VERSION >= 0x040100
81       epoch = "0";
82 #endif
83       version = evr;
84    }
85
86 #define Xstrdup(a) (a) ? strdup(a) : NULL
87    *Epoch = Xstrdup(epoch);
88    *Version = Xstrdup(version);
89    *Release = Xstrdup(release);
90 #undef Xstrdup
91    free(evr);
92 }
93                                                                         /*}}}*/
94 // rpmVS::CmpVersion - Comparison for versions                          /*{{{*/
95 // ---------------------------------------------------------------------
96 /* This fragments the version into E:V-R triples and compares each 
97    portion separately. */
98 int rpmVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
99                                       const char *B,const char *BEnd)
100 {
101    char *AE, *AV, *AR;
102    char *BE, *BV, *BR;
103    int rc = 0;
104    ParseVersion(A, AEnd, &AE, &AV, &AR);
105    ParseVersion(B, BEnd, &BE, &BV, &BR);
106    if (AE && !BE)
107        rc = 1;
108    else if (!AE && BE)
109        rc = -1;
110    else if (AE && BE)
111    {
112       int AEi, BEi;
113       AEi = atoi(AE);
114       BEi = atoi(BE);
115       if (AEi < BEi)
116           rc = -1;
117       else if (AEi > BEi)
118           rc = 1;
119    }
120    if (rc == 0)
121    {
122       rc = rpmvercmp(AV, BV);
123       if (rc == 0) {
124           if (AR && !BR)
125               rc = 1;
126           else if (!AR && BR)
127               rc = -1;
128           else if (AR && BR)
129               rc = rpmvercmp(AR, BR);
130       }
131    }
132    free(AE);free(AV);free(AR);;
133    free(BE);free(BV);free(BR);;
134    return rc;
135 }
136                                                                         /*}}}*/
137 // rpmVS::DoCmpVersionArch - Compare versions, using architecture       /*{{{*/
138 // ---------------------------------------------------------------------
139 /* */
140 int rpmVersioningSystem::DoCmpVersionArch(const char *A,const char *Aend,
141                                           const char *AA,const char *AAend,
142                                           const char *B,const char *Bend,
143                                           const char *BA,const char *BAend)
144 {
145    int rc = DoCmpVersion(A, Aend, B, Bend);
146    if (rc == 0)
147    {
148       int aa = rpmMachineScore(RPM_MACHTABLE_INSTARCH, AA); 
149       int ba = rpmMachineScore(RPM_MACHTABLE_INSTARCH, BA); 
150       if (aa < ba)
151          rc = 1;
152       else if (aa > ba)
153          rc = -1;
154    }
155    return rc;
156 }
157                                                                         /*}}}*/
158 // rpmVS::CheckDep - Check a single dependency                          /*{{{*/
159 // ---------------------------------------------------------------------
160 /* This simply preforms the version comparison and switch based on 
161    operator. If DepVer is 0 then we are comparing against a provides
162    with no version. */
163 bool rpmVersioningSystem::CheckDep(const char *PkgVer,
164                                    int Op,const char *DepVer)
165 {
166    int PkgFlags = RPMSENSE_EQUAL;
167    int DepFlags = 0;
168    bool invert = false;
169    int rc;
170    
171    switch (Op & 0x0F)
172    {
173     case pkgCache::Dep::LessEq:
174       DepFlags = RPMSENSE_LESS|RPMSENSE_EQUAL;
175       break;
176
177     case pkgCache::Dep::GreaterEq:
178       DepFlags = RPMSENSE_GREATER|RPMSENSE_EQUAL;
179       break;
180       
181     case pkgCache::Dep::Less:
182       DepFlags = RPMSENSE_LESS;
183       break;
184       
185     case pkgCache::Dep::Greater:
186       DepFlags = RPMSENSE_GREATER;
187       break;
188
189     case pkgCache::Dep::Equals:
190       DepFlags = RPMSENSE_EQUAL;
191       break;
192       
193     case pkgCache::Dep::NotEquals:
194       DepFlags = RPMSENSE_EQUAL;
195       invert = true;
196       break;
197       
198     default:
199       DepFlags = RPMSENSE_ANY;
200       break;
201    }
202
203 #if RPM_VERSION >= 0x040100
204    rpmds pds = rpmdsSingle(RPMTAG_PROVIDENAME, "", PkgVer, PkgFlags);
205    rpmds dds = rpmdsSingle(RPMTAG_REQUIRENAME, "", DepVer, DepFlags);
206 #if RPM_VERSION >= 0x040201
207    rpmdsSetNoPromote(pds, _rpmds_nopromote);
208    rpmdsSetNoPromote(dds, _rpmds_nopromote);
209 #endif
210    rc = rpmdsCompare(pds, dds);
211    rpmdsFree(pds);
212    rpmdsFree(dds);
213 #else 
214    rc = rpmRangesOverlap("", PkgVer, PkgFlags, "", DepVer, DepFlags);
215 #endif
216     
217    return (!invert && rc) || (invert && !rc);
218 }
219                                                                         /*}}}*/
220 // rpmVS::CheckDep - Check a single dependency                          /*{{{*/
221 // ---------------------------------------------------------------------
222 /* This prototype is a wrapper over CheckDep above. It's useful in the
223    cases where the kind of dependency matters to decide if it matches
224    or not */
225 bool rpmVersioningSystem::CheckDep(const char *PkgVer,
226                                    pkgCache::DepIterator Dep)
227 {
228    if (Dep->Type == pkgCache::Dep::Obsoletes &&
229        (PkgVer == 0 || PkgVer[0] == 0))
230       return false;
231    return CheckDep(PkgVer,Dep->CompareOp,Dep.TargetVer());
232 }
233                                                                         /*}}}*/
234 // rpmVS::UpstreamVersion - Return the upstream version string          /*{{{*/
235 // ---------------------------------------------------------------------
236 /* This strips all the vendor specific information from the version number */
237 string rpmVersioningSystem::UpstreamVersion(const char *Ver)
238 {
239    // Strip off the bit before the first colon
240    const char *I = Ver;
241    for (; *I != 0 && *I != ':'; I++);
242    if (*I == ':')
243       Ver = I + 1;
244    
245    // Chop off the trailing -
246    I = Ver;
247    size_t Last = strlen(Ver);
248    for (; *I != 0; I++)
249       if (*I == '-')
250          Last = I - Ver;
251    
252    return string(Ver,Last);
253 }
254                                                                         /*}}}*/
255
256 #endif /* HAVE_RPM */
257
258 // vim:sts=3:sw=3