2 * Copyright (c) 2007-2009, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
25 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
27 /* debian type version compare */
29 solv_vercmp_deb(const char *s1, const char *q1, const char *s2, const char *q2)
34 c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
35 c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
36 if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
39 c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
41 c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
43 while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
47 c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
48 c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
50 if (c1 >= '0' && c1 <= '9')
52 if (c2 >= '0' && c2 <= '9')
55 return r < 0 ? -1 : 1;
57 c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z') ? c1 : c1 + 256;
58 c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z') ? c2 : c2 + 256;
61 return r < 0 ? -1 : 1;
69 #if !defined(DEBIAN) || defined(MULTI_SEMANTICS)
71 /* rpm type version compare */
72 /* note: the code assumes that *q1 and *q2 are not alphanumeric! */
75 solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
82 while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
83 !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~' && *s1 != '^')
85 while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
86 !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~' && *s2 != '^')
88 if (s1 < q1 && *s1 == '~')
90 if (s2 < q2 && *s2 == '~')
98 if (s2 < q2 && *s2 == '~')
100 if (s1 < q1 && *s1 == '^')
102 if (s2 < q2 && *s2 == '^')
108 return s2 < q2 ? -1 : 1;
110 if (s2 < q2 && *s2 == '^')
111 return s1 < q1 ? 1 : -1;
112 if (s1 >= q1 || s2 >= q2)
114 if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
116 while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
118 while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
120 for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
122 for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
124 r = (e1 - s1) - (e2 - s2);
126 r = strncmp(s1, s2, e1 - s1);
128 return r > 0 ? 1 : -1;
132 for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
134 for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
136 r = (e1 - s1) - (e2 - s2);
139 r = strncmp(s1, s2, e2 - s2);
140 return r >= 0 ? 1 : -1;
144 r = strncmp(s1, s2, e1 - s1);
145 return r <= 0 ? -1 : 1;
147 r = strncmp(s1, s2, e1 - s1);
149 return r > 0 ? 1 : -1;
154 return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
158 solv_vercmp_rpm_notilde(const char *s1, const char *q1, const char *s2, const char *q2)
163 while (s1 < q1 && s2 < q2)
165 while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
166 !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z'))
168 while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
169 !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z'))
171 if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
173 while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
175 while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
177 for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
179 for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
181 r = (e1 - s1) - (e2 - s2);
183 r = strncmp(s1, s2, e1 - s1);
185 return r > 0 ? 1 : -1;
189 for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
191 for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
193 r = (e1 - s1) - (e2 - s2);
196 r = strncmp(s1, s2, e2 - s2);
197 return r >= 0 ? 1 : -1;
201 r = strncmp(s1, s2, e1 - s1);
202 return r <= 0 ? -1 : 1;
204 r = strncmp(s1, s2, e1 - s1);
206 return r > 0 ? 1 : -1;
211 return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
216 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
219 solv_cmp_version_part_haiku(const char *s1, const char *q1, const char *s2,
222 while (s1 < q1 && s2 < q2)
225 const char *part1 = s1, *part2 = s2;
227 /* compare non-number part */
228 while (s1 < q1 && !isdigit(*s1))
230 while (s2 < q2 && !isdigit(*s2))
240 cmp = strncmp(part1, part2, len1 < len2 ? len1 : len2);
246 else if (part2 != s2)
249 /* compare number part */
253 while (s1 < q1 && isdigit(*s1))
255 while (s2 < q2 && isdigit(*s2))
258 while (part1 + 1 < s1 && *part1 == '0')
260 while (part2 + 1 < s2 && *part2 == '0')
270 cmp = strncmp(part1, part2, len1);
275 return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
279 solv_vercmp_haiku(const char *s1, const char *q1, const char *s2, const char *q2)
281 const char *pre1 = s1;
282 const char *pre2 = s2;
285 /* find pre-release separator */
286 while (pre1 != q1 && *pre1 != '~')
288 while (pre2 != q2 && *pre2 != '~')
291 /* compare main versions */
292 cmp = solv_cmp_version_part_haiku(s1, pre1, s2, pre2);
294 return cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
296 /* main versions are equal -- compare pre-release (none is greatest) */
298 return pre2 == q2 ? 0 : 1;
302 cmp = solv_cmp_version_part_haiku(pre1 + 1, q1, pre2 + 1, q2);
303 return cmp == 0 ? 0 : cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
310 * the solv_vercmp variant your system uses.
313 solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
316 return solv_vercmp_deb(s1, q1, s2, q2);
317 #elif defined(ARCHLINUX)
318 return solv_vercmp_rpm_notilde(s1, q1, s2, q2);
320 return solv_vercmp_haiku(s1, q1, s2, q2);
322 return solv_vercmp_rpm(s1, q1, s2, q2);
326 #if defined(MULTI_SEMANTICS)
327 # define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \
328 pool->disttype == DISTTYPE_HAIKU ? &solv_vercmp_haiku : \
330 #elif defined(DEBIAN)
331 # define solv_vercmp solv_vercmp_deb
332 #elif defined(ARCHLINUX)
333 # define solv_vercmp solv_vercmp_rpm_notilde
335 # define solv_vercmp solv_vercmp_haiku
337 # define solv_vercmp solv_vercmp_rpm
340 /* edition (e:v-r) compare */
342 pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
352 if (pool->disttype == DISTTYPE_CONDA)
353 return pool_evrcmp_conda(pool, evr1, evr2, mode);
357 POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
359 for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
361 for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
363 if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
365 /* empty epoch, skip epoch check */
374 /* compare the epoch */
375 if (s1 == evr1 || *s1 != ':')
377 if (s2 == evr2 || *s2 != ':')
381 r = solv_vercmp(evr1, s1, evr2, s2);
389 if (!pool->promoteepoch)
407 /* same epoch, now split into version/release */
408 for (s1 = evr1, r1 = 0; *s1; s1++)
411 for (s2 = evr2, r2 = 0; *s2; s2++)
415 if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
416 r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
420 if (mode == EVRCMP_COMPARE)
427 if (mode == EVRCMP_COMPARE_EVONLY)
429 if (mode == EVRCMP_MATCH_RELEASE)
431 /* rpm treats empty releases as missing, i.e "foo = 4-" is the same as "foo = 4" */
432 if (r1 && r1 + 1 == s1)
434 if (r2 && r2 + 1 == s2)
441 if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2))
443 if (pool->havedistepoch)
446 for (d1 = r1; d1 < s1; d1++)
449 for (d2 = r2; d2 < s2; d2++)
452 /* XXX: promote just in one direction? */
453 r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2);
454 if (r == 0 && d1 < s1 && d2 < s2)
455 r = solv_vercmp(d1 + 1, s1, d2 + 1, s2);
458 r = solv_vercmp(r1, s1, r2, s2);
461 else if (mode == EVRCMP_MATCH_RELEASE)
472 pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode)
474 const char *evr1, *evr2;
475 if (evr1id == evr2id)
477 evr1 = pool_id2str(pool, evr1id);
478 evr2 = pool_id2str(pool, evr2id);
479 return pool_evrcmp_str(pool, evr1, evr2, mode);
483 pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release)
490 evr1 = pool_id2str(pool, evrid);
491 for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
493 if (s1 != evr1 && *s1 == ':')
497 r = solv_vercmp(evr1, s1, epoch, epoch + strlen(epoch));
505 while (*epoch == '0')
510 for (s1 = evr1, r1 = 0; *s1; s1++)
515 r = solv_vercmp(evr1, r1 ? r1 : s1, version, version + strlen(version));
523 r = solv_vercmp(r1 + 1, s1, release, release + strlen(release));