diff options
-rw-r--r-- | lib/libalpm/Makefile.am | 3 | ||||
-rw-r--r-- | lib/libalpm/package.c | 171 | ||||
-rw-r--r-- | lib/libalpm/version.c | 198 |
3 files changed, 200 insertions, 172 deletions
diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 871855ef..3473a73a 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -43,7 +43,8 @@ libalpm_la_SOURCES = \ remove.h remove.c \ sync.h sync.c \ trans.h trans.c \ - util.h util.c + util.h util.c \ + version.c libalpm_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_INFO) libalpm_la_LIBADD = $(LTLIBINTL) diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index ed6d71d0..becbc60f 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -604,177 +604,6 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(pmpkg_t *pkg) return(reqs); } -/** Compare two version strings and determine which one is 'newer'. - * Returns a value comparable to the way strcmp works. Returns 1 - * if a is newer than b, 0 if a and b are the same version, or -1 - * if b is newer than a. - * - * This function has been adopted from the rpmvercmp function located - * at lib/rpmvercmp.c, and was most recently updated against rpm - * version 4.4.2.3. Small modifications have been made to make it more - * consistent with the libalpm coding style. - * - * Keep in mind that the pkgrel is only compared if it is available - * on both versions handed to this function. For example, comparing - * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield - * -1 as expected. This is mainly for supporting versioned dependencies - * that do not include the pkgrel. - */ -int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b) -{ - char oldch1, oldch2; - char *str1, *str2; - char *ptr1, *ptr2; - char *one, *two; - int rc; - int isnum; - int ret = 0; - - ALPM_LOG_FUNC; - - /* libalpm added code. ensure our strings are not null */ - if(!a) { - if(!b) return(0); - return(-1); - } - if(!b) return(1); - - /* easy comparison to see if versions are identical */ - if(strcmp(a, b) == 0) return(0); - - str1 = strdup(a); - str2 = strdup(b); - - one = str1; - two = str2; - - /* loop through each version segment of str1 and str2 and compare them */ - while(*one && *two) { - while(*one && !isalnum((int)*one)) one++; - while(*two && !isalnum((int)*two)) two++; - - /* If we ran to the end of either, we are finished with the loop */ - if(!(*one && *two)) break; - - ptr1 = one; - ptr2 = two; - - /* grab first completely alpha or completely numeric segment */ - /* leave one and two pointing to the start of the alpha or numeric */ - /* segment and walk ptr1 and ptr2 to end of segment */ - if(isdigit((int)*ptr1)) { - while(*ptr1 && isdigit((int)*ptr1)) ptr1++; - while(*ptr2 && isdigit((int)*ptr2)) ptr2++; - isnum = 1; - } else { - while(*ptr1 && isalpha((int)*ptr1)) ptr1++; - while(*ptr2 && isalpha((int)*ptr2)) ptr2++; - isnum = 0; - } - - /* save character at the end of the alpha or numeric segment */ - /* so that they can be restored after the comparison */ - oldch1 = *ptr1; - *ptr1 = '\0'; - oldch2 = *ptr2; - *ptr2 = '\0'; - - /* this cannot happen, as we previously tested to make sure that */ - /* the first string has a non-null segment */ - if (one == ptr1) { - ret = -1; /* arbitrary */ - goto cleanup; - } - - /* take care of the case where the two version segments are */ - /* different types: one numeric, the other alpha (i.e. empty) */ - /* numeric segments are always newer than alpha segments */ - /* XXX See patch #60884 (and details) from bugzilla #50977. */ - if (two == ptr2) { - ret = isnum ? 1 : -1; - goto cleanup; - } - - if (isnum) { - /* this used to be done by converting the digit segments */ - /* to ints using atoi() - it's changed because long */ - /* digit segments can overflow an int - this should fix that. */ - - /* throw away any leading zeros - it's a number, right? */ - while (*one == '0') one++; - while (*two == '0') two++; - - /* whichever number has more digits wins */ - if (strlen(one) > strlen(two)) { - ret = 1; - goto cleanup; - } - if (strlen(two) > strlen(one)) { - ret = -1; - goto cleanup; - } - } - - /* strcmp will return which one is greater - even if the two */ - /* segments are alpha or if they are numeric. don't return */ - /* if they are equal because there might be more segments to */ - /* compare */ - rc = strcmp(one, two); - if (rc) { - ret = rc < 1 ? -1 : 1; - goto cleanup; - } - - /* restore character that was replaced by null above */ - *ptr1 = oldch1; - one = ptr1; - *ptr2 = oldch2; - two = ptr2; - - /* libalpm added code. check if version strings have hit the pkgrel - * portion. depending on which strings have hit, take correct action. - * this is all based on the premise that we only have one dash in - * the version string, and it separates pkgver from pkgrel. */ - if(*ptr1 == '-' && *ptr2 == '-') { - /* no-op, continue comparing since we are equivalent throughout */ - } else if(*ptr1 == '-') { - /* ptr1 has hit the pkgrel and ptr2 has not. continue version - * comparison after stripping the pkgrel from ptr1. */ - *ptr1 = '\0'; - } else if(*ptr2 == '-') { - /* ptr2 has hit the pkgrel and ptr1 has not. continue version - * comparison after stripping the pkgrel from ptr2. */ - *ptr2 = '\0'; - } - } - - /* this catches the case where all numeric and alpha segments have */ - /* compared identically but the segment separating characters were */ - /* different */ - if ((!*one) && (!*two)) { - ret = 0; - goto cleanup; - } - - /* the final showdown. we never want a remaining alpha string to - * beat an empty string. the logic is a bit weird, but: - * - if one is empty and two is not an alpha, two is newer. - * - if one is an alpha, two is newer. - * - otherwise one is newer. - * */ - if ( ( !*one && !isalpha((int)*two) ) - || isalpha((int)*one) ) { - ret = -1; - } else { - ret = 1; - } - -cleanup: - free(str1); - free(str2); - return(ret); -} - /** @} */ pmpkg_t *_alpm_pkg_new(void) diff --git a/lib/libalpm/version.c b/lib/libalpm/version.c new file mode 100644 index 00000000..1c838f41 --- /dev/null +++ b/lib/libalpm/version.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> +#include <ctype.h> + +/* libalpm */ +#include "log.h" +#include "util.h" + +/** Compare two version strings and determine which one is 'newer'. + * Returns a value comparable to the way strcmp works. Returns 1 + * if a is newer than b, 0 if a and b are the same version, or -1 + * if b is newer than a. + * + * This function has been adopted from the rpmvercmp function located + * at lib/rpmvercmp.c, and was most recently updated against rpm + * version 4.4.2.3. Small modifications have been made to make it more + * consistent with the libalpm coding style. + * + * Keep in mind that the pkgrel is only compared if it is available + * on both versions handed to this function. For example, comparing + * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield + * -1 as expected. This is mainly for supporting versioned dependencies + * that do not include the pkgrel. + */ +int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b) +{ + char oldch1, oldch2; + char *str1, *str2; + char *ptr1, *ptr2; + char *one, *two; + int rc; + int isnum; + int ret = 0; + + ALPM_LOG_FUNC; + + /* libalpm added code. ensure our strings are not null */ + if(!a) { + if(!b) return(0); + return(-1); + } + if(!b) return(1); + + /* easy comparison to see if versions are identical */ + if(strcmp(a, b) == 0) return(0); + + str1 = strdup(a); + str2 = strdup(b); + + one = str1; + two = str2; + + /* loop through each version segment of str1 and str2 and compare them */ + while(*one && *two) { + while(*one && !isalnum((int)*one)) one++; + while(*two && !isalnum((int)*two)) two++; + + /* If we ran to the end of either, we are finished with the loop */ + if(!(*one && *two)) break; + + ptr1 = one; + ptr2 = two; + + /* grab first completely alpha or completely numeric segment */ + /* leave one and two pointing to the start of the alpha or numeric */ + /* segment and walk ptr1 and ptr2 to end of segment */ + if(isdigit((int)*ptr1)) { + while(*ptr1 && isdigit((int)*ptr1)) ptr1++; + while(*ptr2 && isdigit((int)*ptr2)) ptr2++; + isnum = 1; + } else { + while(*ptr1 && isalpha((int)*ptr1)) ptr1++; + while(*ptr2 && isalpha((int)*ptr2)) ptr2++; + isnum = 0; + } + + /* save character at the end of the alpha or numeric segment */ + /* so that they can be restored after the comparison */ + oldch1 = *ptr1; + *ptr1 = '\0'; + oldch2 = *ptr2; + *ptr2 = '\0'; + + /* this cannot happen, as we previously tested to make sure that */ + /* the first string has a non-null segment */ + if (one == ptr1) { + ret = -1; /* arbitrary */ + goto cleanup; + } + + /* take care of the case where the two version segments are */ + /* different types: one numeric, the other alpha (i.e. empty) */ + /* numeric segments are always newer than alpha segments */ + /* XXX See patch #60884 (and details) from bugzilla #50977. */ + if (two == ptr2) { + ret = isnum ? 1 : -1; + goto cleanup; + } + + if (isnum) { + /* this used to be done by converting the digit segments */ + /* to ints using atoi() - it's changed because long */ + /* digit segments can overflow an int - this should fix that. */ + + /* throw away any leading zeros - it's a number, right? */ + while (*one == '0') one++; + while (*two == '0') two++; + + /* whichever number has more digits wins */ + if (strlen(one) > strlen(two)) { + ret = 1; + goto cleanup; + } + if (strlen(two) > strlen(one)) { + ret = -1; + goto cleanup; + } + } + + /* strcmp will return which one is greater - even if the two */ + /* segments are alpha or if they are numeric. don't return */ + /* if they are equal because there might be more segments to */ + /* compare */ + rc = strcmp(one, two); + if (rc) { + ret = rc < 1 ? -1 : 1; + goto cleanup; + } + + /* restore character that was replaced by null above */ + *ptr1 = oldch1; + one = ptr1; + *ptr2 = oldch2; + two = ptr2; + + /* libalpm added code. check if version strings have hit the pkgrel + * portion. depending on which strings have hit, take correct action. + * this is all based on the premise that we only have one dash in + * the version string, and it separates pkgver from pkgrel. */ + if(*ptr1 == '-' && *ptr2 == '-') { + /* no-op, continue comparing since we are equivalent throughout */ + } else if(*ptr1 == '-') { + /* ptr1 has hit the pkgrel and ptr2 has not. continue version + * comparison after stripping the pkgrel from ptr1. */ + *ptr1 = '\0'; + } else if(*ptr2 == '-') { + /* ptr2 has hit the pkgrel and ptr1 has not. continue version + * comparison after stripping the pkgrel from ptr2. */ + *ptr2 = '\0'; + } + } + + /* this catches the case where all numeric and alpha segments have */ + /* compared identically but the segment separating characters were */ + /* different */ + if ((!*one) && (!*two)) { + ret = 0; + goto cleanup; + } + + /* the final showdown. we never want a remaining alpha string to + * beat an empty string. the logic is a bit weird, but: + * - if one is empty and two is not an alpha, two is newer. + * - if one is an alpha, two is newer. + * - otherwise one is newer. + * */ + if ( ( !*one && !isalpha((int)*two) ) + || isalpha((int)*one) ) { + ret = -1; + } else { + ret = 1; + } + +cleanup: + free(str1); + free(str2); + return(ret); +} + +/* vim: set ts=2 sw=2 noet: */ |