First draft of make system and name change to apt-pkg
[ntk/apt.git] / apt-pkg / version.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: version.cc,v 1.4 1998/07/12 23:58:42 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 // Version::pkgVersion - Default Constructor /*{{{*/
31 // ---------------------------------------------------------------------
32 /* */
33 pkgVersion::pkgVersion()
34 {
35 }
36 /*}}}*/
37 // Version::operator == - Checks if two versions are equal /*{{{*/
38 // ---------------------------------------------------------------------
39 /* We can't simply perform a string compare because of epochs. */
40 bool pkgVersion::operator ==(const pkgVersion &Vrhs) const
41 {
42 if (pkgVersionCompare(Value.begin(),Value.end(),
43 Vrhs.Value.begin(),Vrhs.Value.end()) == 0)
44 return true;
45 return false;
46 }
47 /*}}}*/
48 // Version::operator < - Checks if this is less than another version /*{{{*/
49 // ---------------------------------------------------------------------
50 /* All other forms of comparision can be built up from this single function.
51 a > b -> b < a
52 a <= b -> !(a > b) -> !(b < a)
53 a >= b -> !(a < b)
54 */
55 bool pkgVersion::operator <(const pkgVersion &Vrhs) const
56 {
57 if (pkgVersionCompare(Value.begin(),Value.end(),
58 Vrhs.Value.begin(),Vrhs.Value.end()) == -1)
59 return true;
60 return false;
61 }
62 /*}}}*/
63 // StrToLong - Convert the string between two iterators to a long /*{{{*/
64 // ---------------------------------------------------------------------
65 /* */
66 static unsigned long StrToLong(const char *begin,const char *end)
67 {
68 char S[40];
69 char *I = S;
70 for (; begin != end && I < S + 40;)
71 *I++ = *begin++;
72 *I = 0;
73 return strtoul(S,0,10);
74 }
75 /*}}}*/
76 // VersionCompare (op) - Greater than comparison for versions /*{{{*/
77 // ---------------------------------------------------------------------
78 /* */
79 int pkgVersionCompare(const char *A, const char *B)
80 {
81 return pkgVersionCompare(A,A + strlen(A),B,B + strlen(B));
82 }
83 int pkgVersionCompare(string A,string B)
84 {
85 return pkgVersionCompare(A.begin(),A.end(),B.begin(),B.end());
86 }
87
88 /*}}}*/
89 // VersionCompare - Greater than comparison for versions /*{{{*/
90 // ---------------------------------------------------------------------
91 /* */
92 int pkgVersionCompare(const char *A, const char *AEnd, const char *B,
93 const char *BEnd)
94 {
95 // lhs = left hand side, rhs = right hand side
96 const char *lhs = A;
97 const char *rhs = B;
98
99 /* Consider epochs. They need special handling because an epoch
100 must not be compared against the first element of the real version.
101 This works okay when both sides have an epoch but when only one
102 does it must compare the missing epoch to 0 */
103 for (;lhs != AEnd && *lhs != ':'; lhs++);
104 for (;rhs != BEnd && *rhs != ':'; rhs++);
105
106 // Parse the epoch out
107 unsigned long lhsEpoch = 0;
108 unsigned long rhsEpoch = 0;
109 if (lhs != AEnd && *lhs == ':')
110 lhsEpoch = StrToLong(A,lhs);
111 if (rhs != BEnd && *rhs == ':')
112 rhsEpoch = StrToLong(B,rhs);
113 if (lhsEpoch != rhsEpoch)
114 {
115 if (lhsEpoch > rhsEpoch)
116 return 1;
117 return -1;
118 }
119
120 /* Iterate over the whole string
121 What this does is to spilt the whole string into groups of
122 numeric and non numeric portions. For instance:
123 a67bhgs89
124 Has 4 portions 'a', '67', 'bhgs', '89'. A more normal:
125 2.7.2-linux-1
126 Has '2', '.', '7', '.' ,'-linux-','1' */
127 lhs = A;
128 rhs = B;
129 while (lhs != AEnd && rhs != BEnd)
130 {
131 // Starting points
132 const char *Slhs = lhs;
133 const char *Srhs = rhs;
134
135 // Compute ending points were we have passed over the portion
136 bool Digit = (isdigit(*lhs) > 0?true:false);
137 for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++);
138 for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++);
139
140 if (Digit == true)
141 {
142 // If the lhs has a digit and the rhs does not then true
143 if (rhs - Srhs == 0)
144 return -1;
145
146 // Generate integers from the strings.
147 unsigned long Ilhs = StrToLong(Slhs,lhs);
148 unsigned long Irhs = StrToLong(Srhs,rhs);
149 if (Ilhs != Irhs)
150 {
151 if (Ilhs > Irhs)
152 return 1;
153 return -1;
154 }
155 }
156 else
157 {
158 // They are equal length so do a straight text compare
159 for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++)
160 {
161 if (*Slhs != *Srhs)
162 {
163 /* We need to compare non alpha chars as higher than alpha
164 chars (a < !) This is so things like 7.6p2-4 and 7.6-0
165 compare higher as well as . and -. I am not sure how
166 the dpkg code manages to achive the != '-' test, but it
167 is necessary. */
168 int lc = *Slhs;
169 int rc = *Srhs;
170 if (isalpha(lc) == 0 && lc != '-') lc += 256;
171 if (isalpha(rc) == 0 && rc != '-') rc += 256;
172 if (lc > rc)
173 return 1;
174 return -1;
175 }
176 }
177
178 // If the lhs is shorter than the right it is 'less'
179 if (lhs - Slhs < rhs - Srhs)
180 return -1;
181
182 // If the lhs is longer than the right it is 'more'
183 if (lhs - Slhs > rhs - Srhs)
184 return 1;
185 }
186 }
187
188 // The strings must be equal
189 if (lhs == AEnd && rhs == BEnd)
190 return 0;
191
192 // lhs is shorter
193 if (lhs == AEnd)
194 return -1;
195
196 // rhs is shorter
197 if (rhs == BEnd)
198 return 1;
199
200 // Shouldnt happen
201 return 1;
202 }
203 /*}}}*/
204 // CheckDep - Check a single dependency /*{{{*/
205 // ---------------------------------------------------------------------
206 /* This simply preforms the version comparison and switch based on
207 operator. */
208 bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op)
209 {
210 if (DepVer == 0)
211 return true;
212 if (PkgVer == 0)
213 return false;
214
215 // Perform the actuall comparision.
216 int Res = pkgVersionCompare(PkgVer,DepVer);
217 switch (Op & 0x0F)
218 {
219 case pkgCache::Dep::LessEq:
220 if (Res <= 0)
221 return true;
222 break;
223
224 case pkgCache::Dep::GreaterEq:
225 if (Res >= 0)
226 return true;
227 break;
228
229 case pkgCache::Dep::Less:
230 if (Res < 0)
231 return true;
232 break;
233
234 case pkgCache::Dep::Greater:
235 if (Res > 0)
236 return true;
237 break;
238
239 case pkgCache::Dep::Equals:
240 if (Res == 0)
241 return true;
242 break;
243
244 case pkgCache::Dep::NotEquals:
245 if (Res != 0)
246 return true;
247 break;
248 }
249
250 return false;
251 }
252 /*}}}*/
253