- get rid of DEBINA_SEMANTICS, add pool->noarchid, add DISTTYPE_ARCH
[platform/upstream/libsolv.git] / src / evr.c
1 /*
2  * Copyright (c) 2007-2009, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * evr.c
10  *
11  * version compare
12  */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include "evr.h"
17 #include "pool.h"
18
19
20
21 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
22
23 /* debian type version compare */
24 int
25 solv_vercmp_deb(const char *s1, const char *q1, const char *s2, const char *q2)
26 {
27   int r, c1, c2;
28   while (1)
29     {
30       c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
31       c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
32       if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
33         {
34           while (c1 == '0')
35             c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
36           while (c2 == '0')
37             c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
38           r = 0;
39           while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
40             {
41               if (!r)
42                 r = c1 - c2;
43               c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
44               c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
45             }
46           if (c1 >= '0' && c1 <= '9')
47             return 1;
48           if (c2 >= '0' && c2 <= '9')
49             return -1;
50           if (r)
51             return r < 0 ? -1 : 1;
52         }
53       c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z')  ? c1 : c1 + 256;
54       c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z')  ? c2 : c2 + 256;
55       r = c1 - c2;
56       if (r)
57         return r < 0 ? -1 : 1;
58       if (!c1)
59         return 0;
60     }
61 }
62
63 #endif
64
65 #if !defined(DEBIAN) || defined(MULTI_SEMANTICS)
66
67 /* rpm type version compare */
68 /* note: the code assumes that *q1 and *q2 are not alphanumeric! */
69
70 int
71 solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
72 {
73   int r = 0;
74   const char *e1, *e2;
75
76   while (s1 < q1 && s2 < q2)
77     {
78       while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
79           !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z'))
80         s1++;
81       while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
82           !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z'))
83         s2++;
84       if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
85         {
86           while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
87             s1++;
88           while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
89             s2++;
90           for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
91             e1++;
92           for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
93             e2++;
94           r = (e1 - s1) - (e2 - s2);
95           if (!r)
96             r = strncmp(s1, s2, e1 - s1);
97           if (r)
98             return r > 0 ? 1 : -1;
99         }
100       else
101         {
102           for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
103             e1++;
104           for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
105             e2++;
106           r = (e1 - s1) - (e2 - s2);
107           if (r > 0)
108             {
109               r = strncmp(s1, s2, e2 - s2);
110               return r >= 0 ? 1 : -1;
111             }
112           if (r < 0)
113             {
114               r = strncmp(s1, s2, e1 - s1);
115               return r <= 0 ? -1 : 1;
116             }
117           r = strncmp(s1, s2, e1 - s1);
118           if (r)
119             return r > 0 ? 1 : -1;
120         }
121       s1 = e1;
122       s2 = e2;
123     }
124   return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
125 }
126
127 #endif
128
129
130 /* 
131  * the solv_vercmp variant your system uses.
132  */
133 int
134 solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
135 {
136 #ifdef DEBIAN
137   return solv_vercmp_deb(s1, q1, s2, q2);
138 #else
139   return solv_vercmp_rpm(s1, q1, s2, q2);
140 #endif
141 }
142
143 #if defined(MULTI_SEMANTICS)
144 # define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : &solv_ver##cmp_rpm))
145 #elif defined(DEBIAN)
146 # define solv_vercmp solv_vercmp_deb
147 #else
148 # define solv_vercmp solv_vercmp_rpm
149 #endif
150
151 /* edition (e:v-r) compare */
152 int
153 pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
154 {
155   int r;
156   const char *s1, *s2;
157   const char *r1, *r2;
158
159   if (evr1 == evr2)
160     return 0;
161
162 #if 0
163   POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
164 #endif
165   for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
166     ;
167   for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
168     ;
169   if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
170     {
171       /* empty epoch, skip epoch check */
172       if (*s1 == ':')
173         evr1 = s1 + 1;
174       if (*s2 == ':')
175         evr2 = s2 + 1;
176       s1 = evr1;
177       s2 = evr2;
178     }
179
180   /* compare the epoch */
181   if (s1 == evr1 || *s1 != ':')
182     s1 = 0;
183   if (s2 == evr2 || *s2 != ':')
184     s2 = 0;
185   if (s1 && s2)
186     {
187       r = solv_vercmp(evr1, s1, evr2, s2);
188       if (r)
189         return r;
190       evr1 = s1 + 1;
191       evr2 = s2 + 1;
192     }
193   else if (s1)
194     {
195       if (!pool->promoteepoch)
196         {
197           while (*evr1 == '0')
198             evr1++;
199           if (*evr1 != ':')
200             return 1;
201         }
202       evr1 = s1 + 1;
203     }
204   else if (s2)
205     {
206       while (*evr2 == '0')
207         evr2++;
208       if (*evr2 != ':')
209         return -1;
210       evr2 = s2 + 1;
211     }
212
213   /* same epoch, now split into version/release */
214   for (s1 = evr1, r1 = 0; *s1; s1++)
215     if (*s1 == '-')
216       r1 = s1;
217   for (s2 = evr2, r2 = 0; *s2; s2++)
218     if (*s2 == '-')
219       r2 = s2;
220
221   r = 0;
222   if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
223     r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
224   if (r)
225     return r;
226
227   if (mode == EVRCMP_COMPARE)
228     {
229       if (!r1 && r2)
230         return -1;
231       if (r1 && !r2)
232         return 1;
233     }
234   if (mode == EVRCMP_COMPARE_EVONLY)
235     return 0;
236   if (r1 && r2)
237     {
238       r1++;
239       r2++;
240       if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2))
241         {
242           if (pool->havedistepoch)
243             {
244               const char *d1, *d2;
245               for (d1 = r1; d1 < s1; d1++)
246                 if (*d1 == ':')
247                   break;
248               for (d2 = r2; d2 < s2; d2++)
249                 if (*d2 == ':')
250                   break;
251               /* XXX: promote just in one direction? */
252               r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2);
253               if (r == 0 && d1 < s1 && d2 < s2)
254                 r = solv_vercmp(d1 + 1, s1, d2 + 1, s2);
255             }
256           else
257             r = solv_vercmp(r1, s1, r2, s2);
258         }
259     }
260   else if (mode == EVRCMP_MATCH_RELEASE)
261     {
262       if (!r1 && r2)
263         return -2;
264       if (r1 && !r2)
265         return 2;
266     }
267   return r;
268 }
269
270 int
271 pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode)
272 {
273   const char *evr1, *evr2;
274   if (evr1id == evr2id)
275     return 0;
276   evr1 = pool_id2str(pool, evr1id);
277   evr2 = pool_id2str(pool, evr2id);
278   return pool_evrcmp_str(pool, evr1, evr2, mode);
279 }
280
281 int
282 pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release)
283 {
284   const char *evr1;
285   const char *s1;
286   const char *r1;
287   int r;
288
289   evr1 = pool_id2str(pool, evrid);
290   for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
291     ;
292   if (s1 != evr1 && *s1 == ':')
293     {
294       if (epoch)
295         {
296           r = solv_vercmp(evr1, s1, epoch, epoch + strlen(epoch));
297           if (r)
298             return r;
299         }
300       evr1 = s1 + 1;
301     }
302   else if (epoch)
303     {
304       while (*epoch == '0')
305         epoch++;
306       if (*epoch)
307         return -1;
308     }
309   for (s1 = evr1, r1 = 0; *s1; s1++)
310     if (*s1 == '-')
311       r1 = s1;
312   if (version)
313     {
314       r = solv_vercmp(evr1, r1 ? r1 : s1, version, version + strlen(version));
315       if (r)
316         return r;
317     }
318   if (release)
319     {
320       if (!r1)
321         return -1;
322       r = solv_vercmp(r1 + 1, s1, release, release + strlen(release));
323       if (r)
324         return r;
325     }
326   return 0;
327 }
328