Fix incorrect comparison between signed/unsigned
[ntk/apt.git] / apt-pkg / deb / debversion.cc
CommitLineData
b2e465d6
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
74c1e22b 3// $Id: debversion.cc,v 1.8 2003/09/10 23:39:49 mdz Exp $
b2e465d6
AL
4/* ######################################################################
5
6 Debian Version - Versioning system for Debian
7
8 This implements the standard Debian versioning system.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
ea542140 13#include <config.h>
b2e465d6
AL
14
15#include <apt-pkg/debversion.h>
16#include <apt-pkg/pkgcache.h>
17
453b82a3
DK
18#include <string.h>
19#include <string>
b2e465d6 20#include <stdlib.h>
233b185f 21#include <ctype.h>
b2e465d6
AL
22 /*}}}*/
23
24debVersioningSystem debVS;
25
26// debVS::debVersioningSystem - Constructor /*{{{*/
27// ---------------------------------------------------------------------
28/* */
29debVersioningSystem::debVersioningSystem()
30{
31 Label = "Standard .deb";
32}
33 /*}}}*/
1e8167a6 34
b2e465d6
AL
35// debVS::CmpFragment - Compare versions /*{{{*/
36// ---------------------------------------------------------------------
09e712b1
AL
37/* This compares a fragment of the version. This is a slightly adapted
38 version of what dpkg uses. */
39#define order(x) ((x) == '~' ? -1 \
40 : isdigit((x)) ? 0 \
41 : !(x) ? 0 \
42 : isalpha((x)) ? (x) \
43 : (x) + 256)
44int debVersioningSystem::CmpFragment(const char *A,const char *AEnd,
b2e465d6
AL
45 const char *B,const char *BEnd)
46{
47 if (A >= AEnd && B >= BEnd)
48 return 0;
49 if (A >= AEnd)
74c1e22b
AL
50 {
51 if (*B == '~') return 1;
b2e465d6 52 return -1;
74c1e22b 53 }
b2e465d6 54 if (B >= BEnd)
74c1e22b
AL
55 {
56 if (*A == '~') return -1;
b2e465d6 57 return 1;
74c1e22b 58 }
09e712b1 59
b2e465d6 60 /* Iterate over the whole string
9373b975 61 What this does is to split the whole string into groups of
b2e465d6
AL
62 numeric and non numeric portions. For instance:
63 a67bhgs89
64 Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
65 2.7.2-linux-1
66 Has '2', '.', '7', '.' ,'-linux-','1' */
67 const char *lhs = A;
68 const char *rhs = B;
69 while (lhs != AEnd && rhs != BEnd)
70 {
1e8167a6 71 int first_diff = 0;
09e712b1 72
7b464090
AL
73 while (lhs != AEnd && rhs != BEnd &&
74 (!isdigit(*lhs) || !isdigit(*rhs)))
09e712b1
AL
75 {
76 int vc = order(*lhs);
77 int rc = order(*rhs);
78 if (vc != rc)
79 return vc - rc;
1e8167a6 80 lhs++; rhs++;
b2e465d6 81 }
b2e465d6 82
09e712b1
AL
83 while (*lhs == '0')
84 lhs++;
85 while (*rhs == '0')
86 rhs++;
87 while (isdigit(*lhs) && isdigit(*rhs))
88 {
89 if (!first_diff)
90 first_diff = *lhs - *rhs;
91 lhs++;
92 rhs++;
1e8167a6 93 }
09e712b1
AL
94
95 if (isdigit(*lhs))
96 return 1;
97 if (isdigit(*rhs))
98 return -1;
99 if (first_diff)
100 return first_diff;
b2e465d6
AL
101 }
102
103 // The strings must be equal
104 if (lhs == AEnd && rhs == BEnd)
105 return 0;
106
107 // lhs is shorter
108 if (lhs == AEnd)
74c1e22b
AL
109 {
110 if (*rhs == '~') return 1;
b2e465d6 111 return -1;
74c1e22b 112 }
b2e465d6
AL
113
114 // rhs is shorter
115 if (rhs == BEnd)
74c1e22b
AL
116 {
117 if (*lhs == '~') return -1;
b2e465d6 118 return 1;
74c1e22b 119 }
09e712b1 120
1e3f4083 121 // Shouldn't happen
b2e465d6
AL
122 return 1;
123}
124 /*}}}*/
125// debVS::CmpVersion - Comparison for versions /*{{{*/
126// ---------------------------------------------------------------------
127/* This fragments the version into E:V-R triples and compares each
128 portion separately. */
129int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd,
130 const char *B,const char *BEnd)
131{
404528bd
DK
132 // Strip off the epoch and compare it
133 const char *lhs = (const char*) memchr(A, ':', AEnd - A);
134 const char *rhs = (const char*) memchr(B, ':', BEnd - B);
135 if (lhs == NULL)
b2e465d6 136 lhs = A;
404528bd 137 if (rhs == NULL)
b2e465d6
AL
138 rhs = B;
139
9373b975
MV
140 // Special case: a zero epoch is the same as no epoch,
141 // so remove it.
142 if (lhs != A)
143 {
144 for (; *A == '0'; ++A);
145 if (A == lhs)
146 {
147 ++A;
148 ++lhs;
149 }
150 }
151 if (rhs != B)
152 {
153 for (; *B == '0'; ++B);
154 if (B == rhs)
155 {
156 ++B;
157 ++rhs;
158 }
159 }
160
b2e465d6
AL
161 // Compare the epoch
162 int Res = CmpFragment(A,lhs,B,rhs);
163 if (Res != 0)
164 return Res;
165
166 // Skip the :
167 if (lhs != A)
168 lhs++;
169 if (rhs != B)
170 rhs++;
171
404528bd
DK
172 // Find the last -
173 const char *dlhs = (const char*) memrchr(lhs, '-', AEnd - lhs);
174 const char *drhs = (const char*) memrchr(rhs, '-', BEnd - rhs);
175 if (dlhs == NULL)
b2e465d6 176 dlhs = AEnd;
404528bd 177 if (drhs == NULL)
b2e465d6
AL
178 drhs = BEnd;
179
180 // Compare the main version
181 Res = CmpFragment(lhs,dlhs,rhs,drhs);
182 if (Res != 0)
183 return Res;
184
185 // Skip the -
186 if (dlhs != lhs)
187 dlhs++;
188 if (drhs != rhs)
189 drhs++;
ea5624c3
DK
190
191 // no debian revision need to be treated like -0
192 if (*(dlhs-1) == '-' && *(drhs-1) == '-')
193 return CmpFragment(dlhs,AEnd,drhs,BEnd);
194 else if (*(dlhs-1) == '-')
195 {
196 const char* null = "0";
197 return CmpFragment(dlhs,AEnd,null, null+1);
198 }
199 else if (*(drhs-1) == '-')
200 {
201 const char* null = "0";
202 return CmpFragment(null, null+1, drhs, BEnd);
203 }
204 else
205 return 0;
b2e465d6
AL
206}
207 /*}}}*/
208// debVS::CheckDep - Check a single dependency /*{{{*/
209// ---------------------------------------------------------------------
210/* This simply preforms the version comparison and switch based on
211 operator. If DepVer is 0 then we are comparing against a provides
212 with no version. */
213bool debVersioningSystem::CheckDep(const char *PkgVer,
214 int Op,const char *DepVer)
215{
216 if (DepVer == 0 || DepVer[0] == 0)
217 return true;
218 if (PkgVer == 0 || PkgVer[0] == 0)
219 return false;
40befb06
DK
220 Op &= 0x0F;
221
885594fc
DK
222 // fast track for (equal) strings [by location] which are by definition equal versions
223 if (PkgVer == DepVer)
224 return Op == pkgCache::Dep::Equals || Op == pkgCache::Dep::LessEq || Op == pkgCache::Dep::GreaterEq;
40befb06 225
1e3f4083 226 // Perform the actual comparison.
885594fc 227 int const Res = CmpVersion(PkgVer, DepVer);
40befb06 228 switch (Op)
b2e465d6
AL
229 {
230 case pkgCache::Dep::LessEq:
231 if (Res <= 0)
232 return true;
233 break;
234
235 case pkgCache::Dep::GreaterEq:
236 if (Res >= 0)
237 return true;
238 break;
239
240 case pkgCache::Dep::Less:
241 if (Res < 0)
242 return true;
243 break;
244
245 case pkgCache::Dep::Greater:
246 if (Res > 0)
247 return true;
248 break;
249
250 case pkgCache::Dep::Equals:
251 if (Res == 0)
252 return true;
253 break;
254
255 case pkgCache::Dep::NotEquals:
256 if (Res != 0)
257 return true;
258 break;
259 }
260
261 return false;
262}
263 /*}}}*/
264// debVS::UpstreamVersion - Return the upstream version string /*{{{*/
265// ---------------------------------------------------------------------
266/* This strips all the debian specific information from the version number */
8f3ba4e8 267std::string debVersioningSystem::UpstreamVersion(const char *Ver)
b2e465d6
AL
268{
269 // Strip off the bit before the first colon
270 const char *I = Ver;
271 for (; *I != 0 && *I != ':'; I++);
272 if (*I == ':')
273 Ver = I + 1;
274
275 // Chop off the trailing -
276 I = Ver;
277 unsigned Last = strlen(Ver);
278 for (; *I != 0; I++)
279 if (*I == '-')
280 Last = I - Ver;
281
8f3ba4e8 282 return std::string(Ver,Last);
b2e465d6
AL
283}
284 /*}}}*/