X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fevr.c;h=a7d43112635c608ac25982323bdcc0bd040f6583;hb=f4f0205fb83dc20d8091827942a408843f78f26d;hp=c8cc940fee9f8dcb8e16b8f11b257e7ef2f7db6d;hpb=ce30350582fa39699ad597d74a21db7e8ebadd58;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/evr.c b/src/evr.c index c8cc940..a7d4311 100644 --- a/src/evr.c +++ b/src/evr.c @@ -11,6 +11,7 @@ * version compare */ +#include #include #include #include "evr.h" @@ -18,15 +19,11 @@ -#if defined(DEBIAN_SEMANTICS) || defined(MULTI_SEMANTICS) - -#ifdef MULTI_SEMANTICS -# define solv_vercmp solv_vercmp_deb -#endif +#if defined(DEBIAN) || defined(MULTI_SEMANTICS) /* debian type version compare */ int -solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2) +solv_vercmp_deb(const char *s1, const char *q1, const char *s2, const char *q2) { int r, c1, c2; while (1) @@ -64,19 +61,86 @@ solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2) } } -#ifdef MULTI_SEMANTICS -# undef solv_vercmp #endif -#endif - -#if !defined(DEBIAN_SEMANTICS) || defined(MULTI_SEMANTICS) +#if !defined(DEBIAN) || defined(MULTI_SEMANTICS) /* rpm type version compare */ /* note: the code assumes that *q1 and *q2 are not alphanumeric! */ int -solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2) +solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2) +{ + int r = 0; + const char *e1, *e2; + + for (;;) + { + while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') && + !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~') + s1++; + while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') && + !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~') + s2++; + if (s1 < q1 && *s1 == '~') + { + if (s2 < q2 && *s2 == '~') + { + s1++; + s2++; + continue; + } + return -1; + } + if (s2 < q2 && *s2 == '~') + return 1; + if (s1 >= q1 || s2 >= q2) + break; + if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9')) + { + while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9') + s1++; + while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9') + s2++; + for (e1 = s1; *e1 >= '0' && *e1 <= '9'; ) + e1++; + for (e2 = s2; *e2 >= '0' && *e2 <= '9'; ) + e2++; + r = (e1 - s1) - (e2 - s2); + if (!r) + r = strncmp(s1, s2, e1 - s1); + if (r) + return r > 0 ? 1 : -1; + } + else + { + for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); ) + e1++; + for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); ) + e2++; + r = (e1 - s1) - (e2 - s2); + if (r > 0) + { + r = strncmp(s1, s2, e2 - s2); + return r >= 0 ? 1 : -1; + } + if (r < 0) + { + r = strncmp(s1, s2, e1 - s1); + return r <= 0 ? -1 : 1; + } + r = strncmp(s1, s2, e1 - s1); + if (r) + return r > 0 ? 1 : -1; + } + s1 = e1; + s2 = e2; + } + return s1 < q1 ? 1 : s2 < q2 ? -1 : 0; +} + +int +solv_vercmp_rpm_notilde(const char *s1, const char *q1, const char *s2, const char *q2) { int r = 0; const char *e1, *e2; @@ -134,8 +198,128 @@ solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2) #endif +#if defined(HAIKU) || defined(MULTI_SEMANTICS) + +static int +solv_cmp_version_part_haiku(const char *s1, const char *q1, const char *s2, + const char *q2) +{ + while (s1 < q1 && s2 < q2) + { + int cmp, len1, len2; + const char *part1 = s1, *part2 = s2; + + /* compare non-number part */ + while (s1 < q1 && !isdigit(*s1)) + s1++; + while (s2 < q2 && !isdigit(*s2)) + s2++; + + if (part1 != s1) + { + if (part2 == s2) + return 1; + + len1 = s1 - part1; + len2 = s2 - part2; + cmp = strncmp(part1, part2, len1 < len2 ? len1 : len2); + if (cmp != 0) + return cmp; + if (len1 != len2) + return len1 - len2; + } + else if (part2 != s2) + return -1; + + /* compare number part */ + part1 = s1; + part2 = s2; + + while (s1 < q1 && isdigit(*s1)) + s1++; + while (s2 < q2 && isdigit(*s2)) + s2++; + + while (part1 + 1 < s1 && *part1 == '0') + part1++; + while (part2 + 1 < s2 && *part2 == '0') + part2++; + + len1 = s1 - part1; + len2 = s2 - part2; + if (len1 != len2) + return len1 - len2; + if (len1 == 0) + return 0; + + cmp = strncmp(part1, part2, len1); + if (cmp != 0) + return cmp; + } + + return s1 < q1 ? 1 : s2 < q2 ? -1 : 0; +} + +int +solv_vercmp_haiku(const char *s1, const char *q1, const char *s2, const char *q2) +{ + const char *pre1 = s1; + const char *pre2 = s2; + int cmp; + + /* find pre-release separator */ + while (pre1 != q1 && *pre1 != '~') + pre1++; + while (pre2 != q2 && *pre2 != '~') + pre2++; + + /* compare main versions */ + cmp = solv_cmp_version_part_haiku(s1, pre1, s2, pre2); + if (cmp != 0) + return cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */ + + /* main versions are equal -- compare pre-release (none is greatest) */ + if (pre1 == q1) + return pre2 == q2 ? 0 : 1; + if (pre2 == q2) + return -1; + + cmp = solv_cmp_version_part_haiku(pre1 + 1, q1, pre2 + 1, q2); + return cmp == 0 ? 0 : cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */ +} + +#endif /* HAIKU */ + + +/* + * the solv_vercmp variant your system uses. + */ +int +solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2) +{ +#if defined(DEBIAN) + return solv_vercmp_deb(s1, q1, s2, q2); +#elif defined(ARCHLINUX) + return solv_vercmp_rpm_notilde(s1, q1, s2, q2); +#elif defined(HAIKU) + return solv_vercmp_haiku(s1, q1, s2, q2); +#else + return solv_vercmp_rpm(s1, q1, s2, q2); +#endif +} + #if defined(MULTI_SEMANTICS) -# define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : &solv_ver##cmp)) +# define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \ + pool->disttype == DISTTYPE_HAIKU ? solv_vercmp_haiku : \ + &solv_ver##cmp_rpm)) +#elif defined(DEBIAN) +# define solv_vercmp solv_vercmp_deb +#elif defined(ARCHLINUX) +# define solv_vercmp solv_vercmp_rpm_notilde +#elif defined(HAIKU) +# define solv_vercmp solv_vercmp_haiku +#else +# define solv_vercmp solv_vercmp_rpm #endif /* edition (e:v-r) compare */ @@ -207,7 +391,6 @@ pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode) for (s2 = evr2, r2 = 0; *s2; s2++) if (*s2 == '-') r2 = s2; - r = 0; if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2))) r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2); @@ -223,10 +406,44 @@ pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode) } if (mode == EVRCMP_COMPARE_EVONLY) return 0; + if (mode == EVRCMP_MATCH_RELEASE) + { + /* rpm treats empty releases as missing, i.e "foo = 4-" is the same as "foo = 4" */ + if (r1 && r1 + 1 == s1) + r1 = 0; + if (r2 && r2 + 1 == s2) + r2 = 0; + } if (r1 && r2) { - if (s1 != ++r1 && s2 != ++r2) - r = solv_vercmp(r1, s1, r2, s2); + r1++; + r2++; + if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2)) + { + if (pool->havedistepoch) + { + const char *d1, *d2; + for (d1 = r1; d1 < s1; d1++) + if (*d1 == ':') + break; + for (d2 = r2; d2 < s2; d2++) + if (*d2 == ':') + break; + /* XXX: promote just in one direction? */ + r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2); + if (r == 0 && d1 < s1 && d2 < s2) + r = solv_vercmp(d1 + 1, s1, d2 + 1, s2); + } + else + r = solv_vercmp(r1, s1, r2, s2); + } + } + else if (mode == EVRCMP_MATCH_RELEASE) + { + if (!r1 && r2) + return -2; + if (r1 && !r2) + return 2; } return r; }