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