mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-08 22:45:43 +00:00
192 lines
5.6 KiB
Diff
192 lines
5.6 KiB
Diff
|
--- src/util/vercmp.c 2009-09-30 03:38:22.000000000 +0200
|
||
|
+++ src/util/vercmp.c 2010-04-07 18:49:13.659173306 +0200
|
||
|
@@ -18,17 +18,184 @@
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
-#include "config.h"
|
||
|
-
|
||
|
#include <stdio.h> /* printf */
|
||
|
+#include <stdlib.h> /* malloc/free */
|
||
|
#include <string.h> /* strncpy */
|
||
|
|
||
|
-#include <alpm.h>
|
||
|
-
|
||
|
#define BASENAME "vercmp"
|
||
|
|
||
|
#define MAX_LEN 255
|
||
|
|
||
|
+/** 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.
|
||
|
+ */
|
||
|
+static int 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;
|
||
|
+
|
||
|
+ /* 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);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
static void usage()
|
||
|
{
|
||
|
fprintf(stderr, "usage: %s <ver1> <ver2>\n\n", BASENAME);
|