Added compile and unpack support to apt-get
[ntk/apt.git] / apt-pkg / version.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: version.cc,v 1.9 1999/04/19 06:03:09 jgg Exp $
4 /* ######################################################################
5
6 Version - Version string
7
8 Version comparing is done using the == and < operators. STL's
9 function.h provides the remaining set of comparitors. A directly
10 callable non-string class version is provided for functions manipulating
11 the cache file (esp the sort function).
12
13 A version is defined to be equal if a case sensitive compare returns
14 that the two strings are the same. For compatibility with the QSort
15 function this version returns -1,0,1.
16
17 ##################################################################### */
18 /*}}}*/
19 // Include Files /*{{{*/
20 #ifdef __GNUG__
21 #pragma implementation "apt-pkg/version.h"
22 #endif
23
24 #include <apt-pkg/version.h>
25 #include <apt-pkg/pkgcache.h>
26
27 #include <stdlib.h>
28 /*}}}*/
29
30 // StrToLong - Convert the string between two iterators to a long /*{{{*/
31 // ---------------------------------------------------------------------
32 /* */
33 static unsigned long StrToLong(const char *begin,const char *end)
34 {
35 char S[40];
36 char *I = S;
37 for (; begin != end && I < S + 40;)
38 *I++ = *begin++;
39 *I = 0;
40 return strtoul(S,0,10);
41 }
42 /*}}}*/
43 // VersionCompare (op) - Greater than comparison for versions /*{{{*/
44 // ---------------------------------------------------------------------
45 /* */
46 int pkgVersionCompare(const char *A, const char *B)
47 {
48 return pkgVersionCompare(A,A + strlen(A),B,B + strlen(B));
49 }
50 int pkgVersionCompare(string A,string B)
51 {
52 return pkgVersionCompare(A.begin(),A.end(),B.begin(),B.end());
53 }
54
55 /*}}}*/
56 // iVersionCompare - Compare versions /*{{{*/
57 // ---------------------------------------------------------------------
58 /* This compares a fragment of the version. */
59 static int iVersionCompare(const char *A, const char *AEnd, const char *B,
60 const char *BEnd)
61 {
62 if (A >= AEnd && B >= BEnd)
63 return 0;
64 if (A >= AEnd)
65 return -1;
66 if (B >= BEnd)
67 return 1;
68
69 /* Iterate over the whole string
70 What this does is to spilt the whole string into groups of
71 numeric and non numeric portions. For instance:
72 a67bhgs89
73 Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
74 2.7.2-linux-1
75 Has '2', '.', '7', '.' ,'-linux-','1' */
76 const char *lhs = A;
77 const char *rhs = B;
78 while (lhs != AEnd && rhs != BEnd)
79 {
80 // Starting points
81 const char *Slhs = lhs;
82 const char *Srhs = rhs;
83
84 // Compute ending points were we have passed over the portion
85 bool Digit = (isdigit(*lhs) > 0?true:false);
86 for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
87 for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
88
89 if (Digit == true)
90 {
91 // If the lhs has a digit and the rhs does not then <
92 if (rhs - Srhs == 0)
93 return -1;
94
95 // Generate integers from the strings.
96 unsigned long Ilhs = StrToLong(Slhs,lhs);
97 unsigned long Irhs = StrToLong(Srhs,rhs);
98 if (Ilhs != Irhs)
99 {
100 if (Ilhs > Irhs)
101 return 1;
102 return -1;
103 }
104 }
105 else
106 {
107 // They are equal length so do a straight text compare
108 for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
109 {
110 if (*Slhs != *Srhs)
111 {
112 /* We need to compare non alpha chars as higher than alpha
113 chars (a < !) */
114 int lc = *Slhs;
115 int rc = *Srhs;
116 if (isalpha(lc) == 0) lc += 256;
117 if (isalpha(rc) == 0) rc += 256;
118 if (lc > rc)
119 return 1;
120 return -1;
121 }
122 }
123
124 // If the lhs is shorter than the right it is 'less'
125 if (lhs - Slhs < rhs - Srhs)
126 return -1;
127
128 // If the lhs is longer than the right it is 'more'
129 if (lhs - Slhs > rhs - Srhs)
130 return 1;
131 }
132 }
133
134 // The strings must be equal
135 if (lhs == AEnd && rhs == BEnd)
136 return 0;
137
138 // lhs is shorter
139 if (lhs == AEnd)
140 return -1;
141
142 // rhs is shorter
143 if (rhs == BEnd)
144 return 1;
145
146 // Shouldnt happen
147 return 1;
148 }
149 /*}}}*/
150 // VersionCompare - Comparison for versions /*{{{*/
151 // ---------------------------------------------------------------------
152 /* This fragments the version into E:V-R triples and compares each
153 portion seperately. */
154 int pkgVersionCompare(const char *A, const char *AEnd, const char *B,
155 const char *BEnd)
156 {
157 // Strip off the epoch and compare it
158 const char *lhs = A;
159 const char *rhs = B;
160 for (;lhs != AEnd && *lhs != ':'; lhs++);
161 for (;rhs != BEnd && *rhs != ':'; rhs++);
162 if (lhs == AEnd)
163 lhs = A;
164 if (rhs == BEnd)
165 rhs = B;
166
167 // Compare the epoch
168 int Res = iVersionCompare(A,lhs,B,rhs);
169 if (Res != 0)
170 return Res;
171
172 // Skip the :
173 if (lhs != A)
174 lhs++;
175 if (rhs != B)
176 rhs++;
177
178 // Find the last -
179 const char *dlhs = AEnd-1;
180 const char *drhs = BEnd-1;
181 for (;dlhs > lhs && *dlhs != '-'; dlhs--);
182 for (;drhs > rhs && *drhs != '-'; drhs--);
183
184 if (dlhs == lhs)
185 dlhs = AEnd;
186 if (drhs == rhs)
187 drhs = BEnd;
188
189 // Compare the main version
190 Res = iVersionCompare(lhs,dlhs,rhs,drhs);
191 if (Res != 0)
192 return Res;
193
194 // Skip the -
195 if (dlhs != lhs)
196 dlhs++;
197 if (drhs != rhs)
198 drhs++;
199 return iVersionCompare(dlhs,AEnd,drhs,BEnd);
200 }
201 /*}}}*/
202 // CheckDep - Check a single dependency /*{{{*/
203 // ---------------------------------------------------------------------
204 /* This simply preforms the version comparison and switch based on
205 operator. */
206 bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
207 {
208 if (DepVer == 0)
209 return true;
210 if (PkgVer == 0)
211 return false;
212
213 // Perform the actuall comparision.
214 int Res = pkgVersionCompare(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 // BaseVersion - Return the upstream version string /*{{{*/
252 // ---------------------------------------------------------------------
253 /* This strips all the debian specific information from the version number */
254 string pkgBaseVersion(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 /*}}}*/