0.7.1
[fapman] / apt-src / debversion.cc
1 /*
2 Apt is copyright 1997, 1998, 1999 Jason Gunthorpe and others.
3 Apt is currently developed by APT Development Team <deity@lists.debian.org>.
4
5 License: GPLv2+
6
7         This program is free software; you can redistribute it and/or modify
8         it under the terms of the GNU General Public License as published by
9         the Free Software Foundation; either version 2 of the License, or
10         (at your option) any later version.
11
12         This program is distributed in the hope that it will be useful,
13         but WITHOUT ANY WARRANTY; without even the implied warranty of
14         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15         GNU General Public License for more details.
16
17         You should have received a copy of the GNU General Public License
18         along with this program; if not, write to the Free Software
19         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21 See /usr/share/common-licenses/GPL-2, or
22 <http://www.gnu.org/copyleft/gpl.txt> for the terms of the latest version
23 of the GNU General Public License.
24 */
25
26
27 // -*- mode: cpp; mode: fold -*-
28 // Description                                                          /*{{{*/
29 // $Id: debversion.cc,v 1.8 2003/09/10 23:39:49 mdz Exp $
30 /* ######################################################################
31
32    Debian Version - Versioning system for Debian
33
34    This implements the standard Debian versioning system.
35    
36    ##################################################################### */
37                                                                         /*}}}*/
38 // Include Files                                                        /*{{{*/
39 #define APT_COMPATIBILITY 986
40
41 #include "debversion.h"
42 #include "pkgcache.h"
43
44 #include <stdlib.h>
45 #include <ctype.h>
46                                                                         /*}}}*/
47
48 debVersioningSystem debVS;
49
50 // debVS::debVersioningSystem - Constructor                             /*{{{*/
51 // ---------------------------------------------------------------------
52 /* */
53 debVersioningSystem::debVersioningSystem()
54 {
55    Label = "Standard .deb";
56 }
57                                                                         /*}}}*/
58
59 // debVS::CmpFragment - Compare versions                                /*{{{*/
60 // ---------------------------------------------------------------------
61 /* This compares a fragment of the version. This is a slightly adapted 
62    version of what dpkg uses. */
63 #define order(x) ((x) == '~' ? -1    \
64                 : isdigit((x)) ? 0   \
65                 : !(x) ? 0           \
66                 : isalpha((x)) ? (x) \
67                 : (x) + 256)
68 int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
69                                      const char *B,const char *BEnd)
70 {
71    if (A >= AEnd && B >= BEnd)
72       return 0;
73    if (A >= AEnd)
74    {
75       if (*B == '~') return 1;
76       return -1;
77    }
78    if (B >= BEnd)
79    {
80       if (*A == '~') return -1;
81       return 1;
82    }
83
84    /* Iterate over the whole string
85       What this does is to split the whole string into groups of
86       numeric and non numeric portions. For instance:
87          a67bhgs89
88       Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
89          2.7.2-linux-1
90       Has '2', '.', '7', '.' ,'-linux-','1' */
91    const char *lhs = A;
92    const char *rhs = B;
93    while (lhs != AEnd && rhs != BEnd)
94    {
95       int first_diff = 0;
96
97       while (lhs != AEnd && rhs != BEnd &&
98              (!isdigit(*lhs) || !isdigit(*rhs)))
99       {
100          int vc = order(*lhs);
101          int rc = order(*rhs);
102          if (vc != rc)
103             return vc - rc;
104          lhs++; rhs++;
105       }
106
107       while (*lhs == '0')
108          lhs++;
109       while (*rhs == '0')
110          rhs++;
111       while (isdigit(*lhs) && isdigit(*rhs))
112       {
113          if (!first_diff)
114             first_diff = *lhs - *rhs;
115          lhs++;
116          rhs++;
117       }
118
119       if (isdigit(*lhs))
120          return 1;
121       if (isdigit(*rhs))
122          return -1;
123       if (first_diff)
124          return first_diff;
125    }
126
127    // The strings must be equal
128    if (lhs == AEnd && rhs == BEnd)
129       return 0;
130
131    // lhs is shorter
132    if (lhs == AEnd)
133    {
134       if (*rhs == '~') return 1;
135       return -1;
136    }
137
138    // rhs is shorter
139    if (rhs == BEnd)
140    {
141       if (*lhs == '~') return -1;
142       return 1;
143    }
144
145    // Shouldnt happen
146    return 1;
147 }
148                                                                         /*}}}*/
149 // debVS::CmpVersion - Comparison for versions                          /*{{{*/
150 // ---------------------------------------------------------------------
151 /* This fragments the version into E:V-R triples and compares each 
152    portion separately. */
153 int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
154                                       const char *B,const char *BEnd)
155 {
156    // Strip off the epoch and compare it 
157    const char *lhs = A;
158    const char *rhs = B;
159    for (;lhs != AEnd && *lhs != ':'; lhs++);
160    for (;rhs != BEnd && *rhs != ':'; rhs++);
161    if (lhs == AEnd)
162       lhs = A;
163    if (rhs == BEnd)
164       rhs = B;
165    
166    // Special case: a zero epoch is the same as no epoch,
167    // so remove it.
168    if (lhs != A)
169    {
170       for (; *A == '0'; ++A);
171       if (A == lhs)
172       {
173          ++A;
174          ++lhs;
175       }
176    }
177    if (rhs != B)
178    {
179       for (; *B == '0'; ++B);
180       if (B == rhs)
181       {
182          ++B;
183          ++rhs;
184       }
185    }
186
187    // Compare the epoch
188    int Res = CmpFragment(A,lhs,B,rhs);
189    if (Res != 0)
190       return Res;
191
192    // Skip the :
193    if (lhs != A)
194       lhs++;
195    if (rhs != B)
196       rhs++;
197    
198    // Find the last - 
199    const char *dlhs = AEnd-1;
200    const char *drhs = BEnd-1;
201    for (;dlhs > lhs && *dlhs != '-'; dlhs--);
202    for (;drhs > rhs && *drhs != '-'; drhs--);
203
204    if (dlhs == lhs)
205       dlhs = AEnd;
206    if (drhs == rhs)
207       drhs = BEnd;
208    
209    // Compare the main version
210    Res = CmpFragment(lhs,dlhs,rhs,drhs);
211    if (Res != 0)
212       return Res;
213    
214    // Skip the -
215    if (dlhs != lhs)
216       dlhs++;
217    if (drhs != rhs)
218       drhs++;
219    
220    return CmpFragment(dlhs,AEnd,drhs,BEnd);
221 }
222                                                                         /*}}}*/
223 // debVS::CheckDep - Check a single dependency                          /*{{{*/
224 // ---------------------------------------------------------------------
225 /* This simply preforms the version comparison and switch based on 
226    operator. If DepVer is 0 then we are comparing against a provides
227    with no version. */
228 bool debVersioningSystem::CheckDep(const char *PkgVer,
229                                    int Op,const char *DepVer)
230 {
231    if (DepVer == 0 || DepVer[0] == 0)
232       return true;
233    if (PkgVer == 0 || PkgVer[0] == 0)
234       return false;
235    
236    // Perform the actual comparision.
237    int Res = CmpVersion(PkgVer,DepVer);
238    switch (Op & 0x0F)
239    {
240       case pkgCache::Dep::LessEq:
241       if (Res <= 0)
242          return true;
243       break;
244       
245       case pkgCache::Dep::GreaterEq:
246       if (Res >= 0)
247          return true;
248       break;
249       
250       case pkgCache::Dep::Less:
251       if (Res < 0)
252          return true;
253       break;
254       
255       case pkgCache::Dep::Greater:
256       if (Res > 0)
257          return true;
258       break;
259       
260       case pkgCache::Dep::Equals:
261       if (Res == 0)
262          return true;
263       break;
264       
265       case pkgCache::Dep::NotEquals:
266       if (Res != 0)
267          return true;
268       break;
269    }
270
271    return false;
272 }
273                                                                         /*}}}*/
274 // debVS::UpstreamVersion - Return the upstream version string          /*{{{*/
275 // ---------------------------------------------------------------------
276 /* This strips all the debian specific information from the version number */
277 string debVersioningSystem::UpstreamVersion(const char *Ver)
278 {
279    // Strip off the bit before the first colon
280    const char *I = Ver;
281    for (; *I != 0 && *I != ':'; I++);
282    if (*I == ':')
283       Ver = I + 1;
284    
285    // Chop off the trailing -
286    I = Ver;
287    unsigned Last = strlen(Ver);
288    for (; *I != 0; I++)
289       if (*I == '-')
290          Last = I - Ver;
291    
292    return string(Ver,Last);
293 }
294                                                                         /*}}}*/