- initial import of revision 374 from cnc
[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 spilt 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    // Compare the epoch
144    int Res = CmpFragment(A,lhs,B,rhs);
145    if (Res != 0)
146       return Res;
147
148    // Skip the :
149    if (lhs != A)
150       lhs++;
151    if (rhs != B)
152       rhs++;
153    
154    // Find the last - 
155    const char *dlhs = AEnd-1;
156    const char *drhs = BEnd-1;
157    for (;dlhs > lhs && *dlhs != '-'; dlhs--);
158    for (;drhs > rhs && *drhs != '-'; drhs--);
159
160    if (dlhs == lhs)
161       dlhs = AEnd;
162    if (drhs == rhs)
163       drhs = BEnd;
164    
165    // Compare the main version
166    Res = CmpFragment(lhs,dlhs,rhs,drhs);
167    if (Res != 0)
168       return Res;
169    
170    // Skip the -
171    if (dlhs != lhs)
172       dlhs++;
173    if (drhs != rhs)
174       drhs++;
175    
176    return CmpFragment(dlhs,AEnd,drhs,BEnd);
177 }
178                                                                         /*}}}*/
179 // debVS::CheckDep - Check a single dependency                          /*{{{*/
180 // ---------------------------------------------------------------------
181 /* This simply preforms the version comparison and switch based on 
182    operator. If DepVer is 0 then we are comparing against a provides
183    with no version. */
184 bool debVersioningSystem::CheckDep(const char *PkgVer,
185                                    int Op,const char *DepVer)
186 {
187    if (DepVer == 0 || DepVer[0] == 0)
188       return true;
189    if (PkgVer == 0 || PkgVer[0] == 0)
190       return false;
191    
192    // Perform the actual comparision.
193    int Res = CmpVersion(PkgVer,DepVer);
194    switch (Op & 0x0F)
195    {
196       case pkgCache::Dep::LessEq:
197       if (Res <= 0)
198          return true;
199       break;
200       
201       case pkgCache::Dep::GreaterEq:
202       if (Res >= 0)
203          return true;
204       break;
205       
206       case pkgCache::Dep::Less:
207       if (Res < 0)
208          return true;
209       break;
210       
211       case pkgCache::Dep::Greater:
212       if (Res > 0)
213          return true;
214       break;
215       
216       case pkgCache::Dep::Equals:
217       if (Res == 0)
218          return true;
219       break;
220       
221       case pkgCache::Dep::NotEquals:
222       if (Res != 0)
223          return true;
224       break;
225    }
226
227    return false;
228 }
229                                                                         /*}}}*/
230 // debVS::UpstreamVersion - Return the upstream version string          /*{{{*/
231 // ---------------------------------------------------------------------
232 /* This strips all the debian specific information from the version number */
233 string debVersioningSystem::UpstreamVersion(const char *Ver)
234 {
235    // Strip off the bit before the first colon
236    const char *I = Ver;
237    for (; *I != 0 && *I != ':'; I++);
238    if (*I == ':')
239       Ver = I + 1;
240    
241    // Chop off the trailing -
242    I = Ver;
243    unsigned Last = strlen(Ver);
244    for (; *I != 0; I++)
245       if (*I == '-')
246          Last = I - Ver;
247    
248    return string(Ver,Last);
249 }
250                                                                         /*}}}*/