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