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