[pacman-dev] [PATCH 1/4] Move vercmp code into a separate file
This will facilitate using this object file on its own in the vercmp tool which will be done in a future commit. The net impact on the generated binaries should not be noticeable after this commit. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/Makefile.am | 3 +- lib/libalpm/package.c | 171 ---------------------------------------- lib/libalpm/version.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 172 deletions(-) create mode 100644 lib/libalpm/version.c diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 871855e..3473a73 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 ed6d71d..becbc60 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 0000000..1c838f4 --- /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: */ -- 1.7.1
It isn't really necessary here and it helps us get rid of some link pollution so we can have a slim vercmp binary. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/version.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/lib/libalpm/version.c b/lib/libalpm/version.c index 1c838f4..fb327df 100644 --- a/lib/libalpm/version.c +++ b/lib/libalpm/version.c @@ -21,7 +21,6 @@ #include <ctype.h> /* libalpm */ -#include "log.h" #include "util.h" /** Compare two version strings and determine which one is 'newer'. @@ -50,8 +49,6 @@ int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b) int isnum; int ret = 0; - ALPM_LOG_FUNC; - /* libalpm added code. ensure our strings are not null */ if(!a) { if(!b) return(0); -- 1.7.1
Include the object file directly from the libalpm version comparison code as it is the only thing we need. This drops the dependency of vercmp on libalpm and all of the stuff we know it drags in. Signed-off-by: Dan McGee <dan@archlinux.org> --- src/util/Makefile.am | 2 +- src/util/vercmp.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 638e276..7dce9dc 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -16,7 +16,7 @@ INCLUDES = -I$(top_srcdir)/lib/libalpm AM_CFLAGS = -pedantic -D_GNU_SOURCE vercmp_SOURCES = vercmp.c -vercmp_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la +vercmp_LDADD = $(top_builddir)/lib/libalpm/version.o testpkg_SOURCES = testpkg.c testpkg_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la diff --git a/src/util/vercmp.c b/src/util/vercmp.c index 778ac55..959dc13 100644 --- a/src/util/vercmp.c +++ b/src/util/vercmp.c @@ -23,12 +23,14 @@ #include <stdio.h> /* printf */ #include <string.h> /* strncpy */ -#include <alpm.h> - #define BASENAME "vercmp" #define MAX_LEN 255 +/* forward declaration, comes from vercmp.o in libalpm source that is linked in + * directly so we don't have any library deps */ +int alpm_pkg_vercmp(const char *a, const char *b); + static void usage() { fprintf(stderr, "usage: %s <ver1> <ver2>\n\n", BASENAME); -- 1.7.1
On 05/05/10 14:45, Dan McGee wrote:
Include the object file directly from the libalpm version comparison code as it is the only thing we need. This drops the dependency of vercmp on libalpm and all of the stuff we know it drags in.
Signed-off-by: Dan McGee<dan@archlinux.org> ---
<snip> After applying the four patches from this patchset:
readelf -d src/util/vercmp
Dynamic section at offset 0xdfc contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libssp.so.0] 0x00000001 (NEEDED) Shared library: [libc.so.6] ... libssp is part of gcc(-libs), so linking to that is probably not a disaster. But is it still not needed for the current Arch vercmp so may be worth looking into. This was of course using -Wl,--as-needed. The list of linked libraries is very long if that is not used (I discovered I had an unaltered makepkg-git.conf...). Maybe we should consider adding --as-needed by default (when supported). Almost ever system that can build pacman will support --as-needed. Allan
On Wed, May 5, 2010 at 1:05 AM, Allan McRae <allan@archlinux.org> wrote:
On 05/05/10 14:45, Dan McGee wrote:
Include the object file directly from the libalpm version comparison code as it is the only thing we need. This drops the dependency of vercmp on libalpm and all of the stuff we know it drags in.
Signed-off-by: Dan McGee<dan@archlinux.org> ---
<snip>
After applying the four patches from this patchset:
readelf -d src/util/vercmp
Dynamic section at offset 0xdfc contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libssp.so.0] 0x00000001 (NEEDED) Shared library: [libc.so.6] ...
libssp is part of gcc(-libs), so linking to that is probably not a disaster. But is it still not needed for the current Arch vercmp so may be worth looking into.
The ssp comes from here: http://projects.archlinux.org/pacman.git/tree/configure.ac#n291 See the GCC_STACK_PROTECT_* macros listed there, which are turned on in debug builds (and for now not in production builds, although there is a feature request in Arch in general to add that).
This was of course using -Wl,--as-needed. The list of linked libraries is very long if that is not used (I discovered I had an unaltered makepkg-git.conf...). Maybe we should consider adding --as-needed by default (when supported). Almost ever system that can build pacman will support --as-needed.
Yeah, sorry I sent these late or I would have noted you needed to use --as-needed. I think for now that is a reasonable compromise, and you might be right about saying we could add that as default. Thanks for testing! -Dan
On 05/05/10 22:55, Dan McGee wrote:
On Wed, May 5, 2010 at 1:05 AM, Allan McRae<allan@archlinux.org> wrote:
On 05/05/10 14:45, Dan McGee wrote:
Include the object file directly from the libalpm version comparison code as it is the only thing we need. This drops the dependency of vercmp on libalpm and all of the stuff we know it drags in.
Signed-off-by: Dan McGee<dan@archlinux.org> ---
<snip>
After applying the four patches from this patchset:
readelf -d src/util/vercmp
Dynamic section at offset 0xdfc contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libssp.so.0] 0x00000001 (NEEDED) Shared library: [libc.so.6] ...
libssp is part of gcc(-libs), so linking to that is probably not a disaster. But is it still not needed for the current Arch vercmp so may be worth looking into.
The ssp comes from here: http://projects.archlinux.org/pacman.git/tree/configure.ac#n291
See the GCC_STACK_PROTECT_* macros listed there, which are turned on in debug builds (and for now not in production builds, although there is a feature request in Arch in general to add that).
Ugh... I can believe I did not think about that! Full ack on all patches then. Allan
Don't explicitly add things to the list that might not need to be there, and get the fallback list of libraries correct. Signed-off-by: Dan McGee <dan@archlinux.org> --- configure.ac | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d0fed48..9760ba8 100644 --- a/configure.ac +++ b/configure.ac @@ -142,8 +142,8 @@ if test "x$internaldownload" = "xyes" ; then AC_MSG_RESULT(yes) AC_DEFINE([INTERNAL_DOWNLOAD], , [Use internal download library]) # Check for a download library if it was actually requested - AC_CHECK_LIB([fetch], [fetchParseURL], [AC_SUBST([LIBS], ["-lfetch -lssl -lcrypto -ldl $LIBS"])], - AC_MSG_ERROR([libfetch is needed to compile with internal download support]), [-lssl -lcrypto -ldl] ) + AC_CHECK_LIB([fetch], [fetchParseURL], , + AC_MSG_ERROR([libfetch is needed to compile with internal download support]), [-lcrypto -ldl] ) # Check if libfetch supports conditional GET # (version >=2.21, struct url has member last_modified) AC_CHECK_MEMBER(struct url.last_modified, , -- 1.7.1
participants (3)
-
Allan McRae
-
Dan McGee
-
Dan McGee