Hello all,

Below, you'll find a patch against the current SVN head to fix a couple of bugs 
in the version comparison code for dpkg. As a brief explanation: (1) the old 
code did not handle epochs that were greater than a single digit, and (2) it 
did not compare alpha() portions of the version string correctly, most notably 
portions that included ~'s and other punctuation.

You'll notice that the solution is almost a mirror image of the official code 
in dpkg.  I looked at it and couldn't think of any better way than that to do 
the comparison.  I added the copyright information at the top to make it 
official.

So it correctly compares versions now and probably more importantly to some:

    text           data     bss     dec     hex filename
  688420           2168    9388  699976   aae48 busybox.orig/busybox
  688273           2168    9388  699829   aadb5 busybox.new/busybox

Enjoy, and let me know if there is anything I missed or need to do a bit 
differently.

-- 
Eugene T. Bordenkircher
[EMAIL PROTECTED] busybox.orig/archival/dpkg.c  2008-11-19 12:48:29.000000000 
-0800
+++ busybox.new/archival/dpkg.c 2008-11-19 12:56:43.000000000 -0800
@@ -6,6 +6,10 @@
   *  written by glenn mcgrath with the help of others
   *  copyright (c) 2001 by glenn mcgrath
   *
+ *  parts of the version comparison code is plucked from the real dpkg
+ *  application which is licensed GPLv2 and
+ *  copyright (c) 1995 Ian Jackson <[EMAIL PROTECTED]>
+ *
   *  started life as a busybox implementation of udpkg
   *
   * licensed under gplv2 or later, see file license in this tarball for 
details.
@@ -28,6 +32,8 @@
  #include <fnmatch.h>
  #include "unarchive.h"

+#include <ctype.h>
+
  /* note: if you vary hash_prime sizes be aware,
   * 1) tweaking these will have a big effect on how much memory this program 
uses.
   * 2) for computational efficiency these hash tables should be at least 20%
@@ -183,60 +189,41 @@
        return probe_address;
  }

-/* Need to rethink version comparison, maybe the official dpkg has something i 
can use ? */
-static int version_compare_part(const char *version1, const char *version2)
+/* This code is taken from dpkg and was converted to a function to save
+ * a few bytes in the text section of busybox */
+static int order( char x )
  {
-       int upstream_len1 = 0;
-       int upstream_len2 = 0;
-       char *name1_char;
-       char *name2_char;
-       int len1 = 0;
-       int len2 = 0;
-       int tmp_int;
-       int ver_num1;
-       int ver_num2;
-
-       if (version1 == NULL) {
-               version1 = xstrdup("");
-       }
-       if (version2 == NULL) {
-               version2 = xstrdup("");
-       }
-       upstream_len1 = strlen(version1);
-       upstream_len2 = strlen(version2);
-
-       while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
-               /* Compare non-digit section */
-               tmp_int = strcspn(&version1[len1], "0123456789");
-               name1_char = xstrndup(&version1[len1], tmp_int);
-               len1 += tmp_int;
-               tmp_int = strcspn(&version2[len2], "0123456789");
-               name2_char = xstrndup(&version2[len2], tmp_int);
-               len2 += tmp_int;
-               tmp_int = strcmp(name1_char, name2_char);
-               free(name1_char);
-               free(name2_char);
-               if (tmp_int != 0) {
-                       return tmp_int;
-               }
-
-               /* Compare digits */
-               tmp_int = strspn(&version1[len1], "0123456789");
-               name1_char = xstrndup(&version1[len1], tmp_int);
-               len1 += tmp_int;
-               tmp_int = strspn(&version2[len2], "0123456789");
-               name2_char = xstrndup(&version2[len2], tmp_int);
-               len2 += tmp_int;
-               ver_num1 = atoi(name1_char);
-               ver_num2 = atoi(name2_char);
-               free(name1_char);
-               free(name2_char);
-               if (ver_num1 < ver_num2) {
-                       return -1;
+       return ( x == '~' ? -1
+                        : isdigit(x) ? 0
+                        : !(x) ? 0
+                        : isalpha(x) ? x
+                        : x + 256 );
                }
-               if (ver_num1 > ver_num2) {
-                       return 1;
+
+/* This code is taken from dpkg and modified slightly to work with busybox */
+static int version_compare_part(const char *val, const char *ref)
+{
+       if (!val) val = "";
+       if (!ref) ref = "";
+
+       while (*val || *ref) {
+               int first_diff = 0;
+
+               while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) {
+                       int vc = order(*val), rc = order(*ref);
+                       if (vc != rc) return vc - rc;
+                       val++; ref++;
+               }
+
+               while ( *val == '0' ) val++;
+               while ( *ref == '0' ) ref++;
+               while (isdigit(*val) && isdigit(*ref)) {
+                       if (!first_diff) first_diff = *val - *ref;
+                       val++; ref++;
                }
+               if (isdigit(*val)) return 1;
+               if (isdigit(*ref)) return -1;
+               if (first_diff) return first_diff;
        }
        return 0;
  }
@@ -250,27 +237,23 @@
        char *ch_ver1 = name_hashtable[ver1];
        char *ch_ver2 = name_hashtable[ver2];

-       char epoch1, epoch2;
+       unsigned long epoch1 = 0, epoch2 = 0;
+       char *colon;
        char *deb_ver1, *deb_ver2;
-       char *ver1_ptr, *ver2_ptr;
        char *upstream_ver1;
        char *upstream_ver2;
        int result;

        /* Compare epoch */
-       if (ch_ver1[1] == ':') {
-               epoch1 = ch_ver1[0];
-               ver1_ptr = strchr(ch_ver1, ':') + 1;
-       } else {
-               epoch1 = '0';
-               ver1_ptr = ch_ver1;
-       }
-       if (ch_ver2[1] == ':') {
-               epoch2 = ch_ver2[0];
-               ver2_ptr = strchr(ch_ver2, ':') + 1;
-       } else {
-               epoch2 = '0';
-               ver2_ptr = ch_ver2;
+       colon = strchr(ch_ver1,':');
+       if (colon) {
+               epoch1 = atoi(ch_ver1);
+               ch_ver1 = colon+1;
+       }
+       colon = strchr(ch_ver2,':');
+       if (colon) {
+               epoch2 = atoi(ch_ver2);
+               ch_ver2 = colon+1;
        }
        if (epoch1 < epoch2) {
                return -1;
@@ -280,8 +263,8 @@
        }

        /* Compare upstream version */
-       upstream_ver1 = xstrdup(ver1_ptr);
-       upstream_ver2 = xstrdup(ver2_ptr);
+       upstream_ver1 = xstrdup(ch_ver1);
+       upstream_ver2 = xstrdup(ch_ver2);

        /* Chop off debian version, and store for later use */
        deb_ver1 = strrchr(upstream_ver1, '-');

----------------------------
_______________________________________________
busybox mailing list
busybox@busybox.net
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to