autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: AS_VERSION_COMPARE


From: Paul Eggert
Subject: Re: AS_VERSION_COMPARE
Date: Thu, 16 Jun 2005 14:10:34 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.4 (gnu/linux)

Derek Price <address@hidden> writes:

> +[if test "x[$1]" = "x[$2]"; then

I'd rather avoid the need for the quote (") characters here, if possible.

> +                 sed 's/\([abcedfghi]\)/.\1/;

"e" comes before "d"?  :-)

Anyway, there's gotta be a better way to compare version numbers.  The
algorithm should be compatible with glibc strverscmp, and it'd be nice
to do it in one process.  Also, there should be test cases.

I installed the following; would you like to give it a try?

2005-06-16  Paul Eggert  <address@hidden>

        * lib/m4sugar/m4sh.m4 (_AS_VERSION_COMPARE_PREPARE): New macro.
        (AS_VERSION_COMPARE): New macro.  The API is taken from CVS,
        but the implementation is entirely different and is designed
        to be compatible with glibc strverscmp.
        * tests/m4sh.at (AS_VERSION_COMPARE): New test.

Index: lib/m4sugar/m4sh.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/m4sugar/m4sh.m4,v
retrieving revision 1.146
diff -p -u -r1.146 m4sh.m4
--- lib/m4sugar/m4sh.m4 11 Jun 2005 06:05:12 -0000      1.146
+++ lib/m4sugar/m4sh.m4 16 Jun 2005 20:57:56 -0000
@@ -1022,6 +1022,83 @@ _AS_PATH_WALK([$PATH], [echo "PATH: $as_
 }])
 
 
+# _AS_VERSION_COMPARE_PREPARE
+# ---------------------------
+# Output variables for comparing version numbers.
+m4_defun([_AS_VERSION_COMPARE_PREPARE],
+[[as_awk_strverscmp='
+  END {
+    while (length(v1) || length(v2)) {
+      # Set d1 to be the next thing to compare from v1, and likewise for d2.
+      # Normally this is a single character, but if v1 and v2 contain digits,
+      # compare them as integers and fractions as strverscmp does.
+      d1 = v1; sub(/[^0-9].*/, "", d1); len1 = length(d1)
+      d2 = v2; sub(/[^0-9].*/, "", d2); len2 = length(d2)
+      if (len1 && len2) {
+       # v1 and v2 both have leading digits.
+       v1 = substr(v1, len1 + 1)
+       v2 = substr(v2, len1 + 1)
+       if (d1 ~ /^0/) {
+         if (d2 ~ /^0/) {
+           # Compare two fractions.
+           do {
+             d1 = substr(d1, 2); len1--
+             d2 = substr(d2, 2); len2--
+           } while (d1 ~ /^0/ && d2 ~ /^0/);
+           if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == 
substr(d2, 1, 1))) {
+             # The two components differ in length, and the common prefix
+             # contains only leading zeros.  Consider the longer to be less.
+             d1 = -len1
+             d2 = -len2
+           } else {
+             # Otherwise, compare as strings.
+             d1 = "x" d1
+             d2 = "x" d2
+           }
+         } else {
+           # A fraction is less than an integer.
+           exit 1
+         }
+       } else {
+         if (d2 ~ /^0/) {
+           # An integer is greater than a fraction.
+           exit 2
+         } else {
+           # Compare two integers.
+           d1 += 0
+           d2 += 0
+         }
+       }
+      } else {
+       # The normal case, without worrying about digits.
+       if (v1 == "") d1 = v1; else { d1 = substr(v1, 1, 1); v1 = substr(v1,2) }
+       if (v2 == "") d2 = v2; else { d2 = substr(v2, 1, 1); v2 = substr(v2,2) }
+      }
+      if (d1 < d2) exit 1
+      if (d1 > d2) exit 2
+    }
+  }
+']])
+
+# AS_VERSION_COMPARE(VERSION-1, VERSION-2,
+#                    [ACTION-IF-LESS], [ACTION-IF-EQUAL], [ACTION-IF-GREATER])
+# -----------------------------------------------------------------------------
+# Compare two strings possibly containing shell variables as version strings.
+m4_defun([AS_VERSION_COMPARE],
+[AS_REQUIRE([_$0_PREPARE])dnl
+as_arg_v1=$1
+as_arg_v2=$2
+dnl This usage is portable even to ancient awk,
+dnl so don't worry about finding a "nice" awk version.
+awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null
+case $? in
+1) $3;;
+0) $4;;
+2) $5;;
+esac[]dnl
+])
+
+
 # AS_HELP_STRING(LHS, RHS, [COLUMN])
 # ----------------------------------
 #
Index: tests/m4sh.at
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/m4sh.at,v
retrieving revision 1.41
diff -p -u -r1.41 m4sh.at
--- tests/m4sh.at       14 May 2005 07:00:40 -0000      1.41
+++ tests/m4sh.at       16 Jun 2005 20:57:56 -0000
@@ -244,6 +244,52 @@ AT_CLEANUP
 
 
 
+## -------------------- ##
+## AS_VERSION_COMPARE.  ##
+## -------------------- ##
+
+# Build nested dirs.
+AT_SETUP([AS@&address@hidden)
+
+AT_DATA_M4SH([script.as],
+[[AS_INIT
+
+m4_define([VERSION_COMPARE_TEST],
+[AS_VERSION_COMPARE([$1], [$3], [result='<'], [result='='], [result='>'])
+test "X$result" = "X$2" ||
+  AS_ERROR([version $1 $result $3; should be $1 $2 $3])
+m4_if([$1], <,
+[AS_VERSION_COMPARE([$3], [$1], [result='<'], [result='='], [result='>'])
+test "X$result" = "X>" ||
+  AS_ERROR([version $3 $result $1; should be $3 > $1])])])
+
+VERSION_COMPARE_TEST([], =, [])
+VERSION_COMPARE_TEST([1.0], =, [1.0])
+VERSION_COMPARE_TEST([alpha-1.0], =, [alpha-1.0])
+
+# These tests are taken from libc/string/tst-svc.expect.
+tst_svc_expect='
+  000 001 00 00a 01 01a 0 0a 2.8 2.8-0.4 20 21 22 212 CP037 CP345 CP1257
+  foo foo-0.4 foo-0.4a foo-0.4b foo-0.5 foo-0.10.5 foo-3.01 foo-3.0
+  foo-3.0.0 foo-3.0.1 foo-3.2 foo-3.10 foo00 foo0
+'
+test1=''
+for test2 in $tst_svc_expect; do
+  VERSION_COMPARE_TEST([$test1], <, [$test2])
+  test1=$test2
+done
+
+AS_EXIT(0)
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([./script])
+
+AT_CLEANUP
+
+
+
+
 ## ----------------------------- ##
 ## Negated classes in globbing.  ##
 ## ----------------------------- ##




reply via email to

[Prev in Thread] Current Thread [Next in Thread]