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