Imported Upstream version 0.7.2
[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 <ctype.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include "evr.h"
18 #include "pool.h"
19
20
21
22 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
23
24 /* debian type version compare */
25 int
26 solv_vercmp_deb(const char *s1, const char *q1, const char *s2, const char *q2)
27 {
28   int r, c1, c2;
29   while (1)
30     {
31       c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
32       c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
33       if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
34         {
35           while (c1 == '0')
36             c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
37           while (c2 == '0')
38             c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
39           r = 0;
40           while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
41             {
42               if (!r)
43                 r = c1 - c2;
44               c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
45               c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
46             }
47           if (c1 >= '0' && c1 <= '9')
48             return 1;
49           if (c2 >= '0' && c2 <= '9')
50             return -1;
51           if (r)
52             return r < 0 ? -1 : 1;
53         }
54       c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z')  ? c1 : c1 + 256;
55       c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z')  ? c2 : c2 + 256;
56       r = c1 - c2;
57       if (r)
58         return r < 0 ? -1 : 1;
59       if (!c1)
60         return 0;
61     }
62 }
63
64 #endif
65
66 #if !defined(DEBIAN) || defined(MULTI_SEMANTICS)
67
68 /* rpm type version compare */
69 /* note: the code assumes that *q1 and *q2 are not alphanumeric! */
70
71 int
72 solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
73 {
74   int r = 0;
75   const char *e1, *e2;
76
77   for (;;)
78     {
79       while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
80           !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~' && *s1 != '^')
81         s1++;
82       while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
83           !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~' && *s2 != '^')
84         s2++;
85       if (s1 < q1 && *s1 == '~')
86         {
87           if (s2 < q2 && *s2 == '~')
88             {
89               s1++;
90               s2++;
91               continue;
92             }
93           return -1;
94         }
95       if (s2 < q2 && *s2 == '~')
96         return 1;
97       if (s1 < q1 && *s1 == '^')
98         {
99           if (s2 < q2 && *s2 == '^')
100             {
101               s1++;
102               s2++;
103               continue;
104             }
105           return s2 < q2 ? -1 : 1;
106         }
107       if (s2 < q2 && *s2 == '^')
108         return s1 < q1 ? 1 : -1;
109       if (s1 >= q1 || s2 >= q2)
110         break;
111       if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
112         {
113           while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
114             s1++;
115           while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
116             s2++;
117           for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
118             e1++;
119           for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
120             e2++;
121           r = (e1 - s1) - (e2 - s2);
122           if (!r)
123             r = strncmp(s1, s2, e1 - s1);
124           if (r)
125             return r > 0 ? 1 : -1;
126         }
127       else
128         {
129           for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
130             e1++;
131           for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
132             e2++;
133           r = (e1 - s1) - (e2 - s2);
134           if (r > 0)
135             {
136               r = strncmp(s1, s2, e2 - s2);
137               return r >= 0 ? 1 : -1;
138             }
139           if (r < 0)
140             {
141               r = strncmp(s1, s2, e1 - s1);
142               return r <= 0 ? -1 : 1;
143             }
144           r = strncmp(s1, s2, e1 - s1);
145           if (r)
146             return r > 0 ? 1 : -1;
147         }
148       s1 = e1;
149       s2 = e2;
150     }
151   return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
152 }
153
154 int
155 solv_vercmp_rpm_notilde(const char *s1, const char *q1, const char *s2, const char *q2)
156 {
157   int r = 0;
158   const char *e1, *e2;
159
160   while (s1 < q1 && s2 < q2)
161     {
162       while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
163           !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z'))
164         s1++;
165       while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
166           !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z'))
167         s2++;
168       if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
169         {
170           while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
171             s1++;
172           while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
173             s2++;
174           for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
175             e1++;
176           for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
177             e2++;
178           r = (e1 - s1) - (e2 - s2);
179           if (!r)
180             r = strncmp(s1, s2, e1 - s1);
181           if (r)
182             return r > 0 ? 1 : -1;
183         }
184       else
185         {
186           for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
187             e1++;
188           for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
189             e2++;
190           r = (e1 - s1) - (e2 - s2);
191           if (r > 0)
192             {
193               r = strncmp(s1, s2, e2 - s2);
194               return r >= 0 ? 1 : -1;
195             }
196           if (r < 0)
197             {
198               r = strncmp(s1, s2, e1 - s1);
199               return r <= 0 ? -1 : 1;
200             }
201           r = strncmp(s1, s2, e1 - s1);
202           if (r)
203             return r > 0 ? 1 : -1;
204         }
205       s1 = e1;
206       s2 = e2;
207     }
208   return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
209 }
210
211 #endif
212
213 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
214
215 static int
216 solv_cmp_version_part_haiku(const char *s1, const char *q1, const char *s2,
217   const char *q2)
218 {
219   while (s1 < q1 && s2 < q2)
220     {
221       int cmp, len1, len2;
222       const char *part1 = s1, *part2 = s2;
223
224       /* compare non-number part */
225       while (s1 < q1 && !isdigit(*s1))
226         s1++;
227       while (s2 < q2 && !isdigit(*s2))
228         s2++;
229
230       if (part1 != s1)
231         {
232           if (part2 == s2)
233             return 1;
234
235           len1 = s1 - part1;
236           len2 = s2 - part2;
237           cmp = strncmp(part1, part2, len1 < len2 ? len1 : len2);
238           if (cmp != 0)
239             return cmp;
240           if (len1 != len2)
241             return len1 - len2;
242        }
243       else if (part2 != s2)
244         return -1;
245
246       /* compare number part */
247       part1 = s1;
248       part2 = s2;
249
250       while (s1 < q1 && isdigit(*s1))
251         s1++;
252       while (s2 < q2 && isdigit(*s2))
253         s2++;
254
255       while (part1 + 1 < s1 && *part1 == '0')
256         part1++;
257       while (part2 + 1 < s2 && *part2 == '0')
258         part2++;
259
260       len1 = s1 - part1;
261       len2 = s2 - part2;
262       if (len1 != len2)
263         return len1 - len2;
264       if (len1 == 0)
265         return 0;
266
267       cmp = strncmp(part1, part2, len1);
268       if (cmp != 0)
269        return cmp;
270     }
271
272   return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
273 }
274
275 int
276 solv_vercmp_haiku(const char *s1, const char *q1, const char *s2, const char *q2)
277 {
278   const char *pre1 = s1;
279   const char *pre2 = s2;
280   int cmp;
281
282   /* find pre-release separator */
283   while (pre1 != q1 && *pre1 != '~')
284     pre1++;
285   while (pre2 != q2 && *pre2 != '~')
286     pre2++;
287
288   /* compare main versions */
289   cmp = solv_cmp_version_part_haiku(s1, pre1, s2, pre2);
290   if (cmp != 0)
291     return cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
292
293   /* main versions are equal -- compare pre-release (none is greatest) */
294   if (pre1 == q1)
295     return pre2 == q2 ? 0 : 1;
296   if (pre2 == q2)
297     return -1;
298
299   cmp = solv_cmp_version_part_haiku(pre1 + 1, q1, pre2 + 1, q2);
300   return cmp == 0 ? 0 : cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
301 }
302
303 #endif /* HAIKU */
304
305
306 /*
307  * the solv_vercmp variant your system uses.
308  */
309 int
310 solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
311 {
312 #if defined(DEBIAN)
313   return solv_vercmp_deb(s1, q1, s2, q2);
314 #elif defined(ARCHLINUX)
315   return solv_vercmp_rpm_notilde(s1, q1, s2, q2);
316 #elif defined(HAIKU)
317   return solv_vercmp_haiku(s1, q1, s2, q2);
318 #else
319   return solv_vercmp_rpm(s1, q1, s2, q2);
320 #endif
321 }
322
323 #if defined(MULTI_SEMANTICS)
324 # define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \
325                         pool->disttype == DISTTYPE_HAIKU ? solv_vercmp_haiku : \
326                         &solv_ver##cmp_rpm))
327 #elif defined(DEBIAN)
328 # define solv_vercmp solv_vercmp_deb
329 #elif defined(ARCHLINUX)
330 # define solv_vercmp solv_vercmp_rpm_notilde
331 #elif defined(HAIKU)
332 # define solv_vercmp solv_vercmp_haiku
333 #else
334 # define solv_vercmp solv_vercmp_rpm
335 #endif
336
337 /* edition (e:v-r) compare */
338 int
339 pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
340 {
341   int r;
342   const char *s1, *s2;
343   const char *r1, *r2;
344
345   if (evr1 == evr2)
346     return 0;
347
348 #if 0
349   POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
350 #endif
351   for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
352     ;
353   for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
354     ;
355   if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
356     {
357       /* empty epoch, skip epoch check */
358       if (*s1 == ':')
359         evr1 = s1 + 1;
360       if (*s2 == ':')
361         evr2 = s2 + 1;
362       s1 = evr1;
363       s2 = evr2;
364     }
365
366   /* compare the epoch */
367   if (s1 == evr1 || *s1 != ':')
368     s1 = 0;
369   if (s2 == evr2 || *s2 != ':')
370     s2 = 0;
371   if (s1 && s2)
372     {
373       r = solv_vercmp(evr1, s1, evr2, s2);
374       if (r)
375         return r;
376       evr1 = s1 + 1;
377       evr2 = s2 + 1;
378     }
379   else if (s1)
380     {
381       if (!pool->promoteepoch)
382         {
383           while (*evr1 == '0')
384             evr1++;
385           if (*evr1 != ':')
386             return 1;
387         }
388       evr1 = s1 + 1;
389     }
390   else if (s2)
391     {
392       while (*evr2 == '0')
393         evr2++;
394       if (*evr2 != ':')
395         return -1;
396       evr2 = s2 + 1;
397     }
398
399   /* same epoch, now split into version/release */
400   for (s1 = evr1, r1 = 0; *s1; s1++)
401     if (*s1 == '-')
402       r1 = s1;
403   for (s2 = evr2, r2 = 0; *s2; s2++)
404     if (*s2 == '-')
405       r2 = s2;
406   r = 0;
407   if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
408     r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
409   if (r)
410     return r;
411
412   if (mode == EVRCMP_COMPARE)
413     {
414       if (!r1 && r2)
415         return -1;
416       if (r1 && !r2)
417         return 1;
418     }
419   if (mode == EVRCMP_COMPARE_EVONLY)
420     return 0;
421   if (mode == EVRCMP_MATCH_RELEASE)
422     {
423       /* rpm treats empty releases as missing, i.e "foo = 4-" is the same as "foo = 4" */
424       if (r1 && r1 + 1 == s1)
425         r1 = 0;
426       if (r2 && r2 + 1 == s2)
427         r2 = 0;
428     }
429   if (r1 && r2)
430     {
431       r1++;
432       r2++;
433       if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2))
434         {
435           if (pool->havedistepoch)
436             {
437               const char *d1, *d2;
438               for (d1 = r1; d1 < s1; d1++)
439                 if (*d1 == ':')
440                   break;
441               for (d2 = r2; d2 < s2; d2++)
442                 if (*d2 == ':')
443                   break;
444               /* XXX: promote just in one direction? */
445               r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2);
446               if (r == 0 && d1 < s1 && d2 < s2)
447                 r = solv_vercmp(d1 + 1, s1, d2 + 1, s2);
448             }
449           else
450             r = solv_vercmp(r1, s1, r2, s2);
451         }
452     }
453   else if (mode == EVRCMP_MATCH_RELEASE)
454     {
455       if (!r1 && r2)
456         return -2;
457       if (r1 && !r2)
458         return 2;
459     }
460   return r;
461 }
462
463 int
464 pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode)
465 {
466   const char *evr1, *evr2;
467   if (evr1id == evr2id)
468     return 0;
469   evr1 = pool_id2str(pool, evr1id);
470   evr2 = pool_id2str(pool, evr2id);
471   return pool_evrcmp_str(pool, evr1, evr2, mode);
472 }
473
474 int
475 pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release)
476 {
477   const char *evr1;
478   const char *s1;
479   const char *r1;
480   int r;
481
482   evr1 = pool_id2str(pool, evrid);
483   for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
484     ;
485   if (s1 != evr1 && *s1 == ':')
486     {
487       if (epoch)
488         {
489           r = solv_vercmp(evr1, s1, epoch, epoch + strlen(epoch));
490           if (r)
491             return r;
492         }
493       evr1 = s1 + 1;
494     }
495   else if (epoch)
496     {
497       while (*epoch == '0')
498         epoch++;
499       if (*epoch)
500         return -1;
501     }
502   for (s1 = evr1, r1 = 0; *s1; s1++)
503     if (*s1 == '-')
504       r1 = s1;
505   if (version)
506     {
507       r = solv_vercmp(evr1, r1 ? r1 : s1, version, version + strlen(version));
508       if (r)
509         return r;
510     }
511   if (release)
512     {
513       if (!r1)
514         return -1;
515       r = solv_vercmp(r1 + 1, s1, release, release + strlen(release));
516       if (r)
517         return r;
518     }
519   return 0;
520 }
521