Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] fix/simplify is-at-least



I would like to fix/simplify is-at-least, but if version
string contains non-digit characters it behaves differently
from the current version (not always but in a few cases),
as described in [3] below. If there is a concern that these
changes would break existing code, please let me know.

[1] is-at-least gives wrong return code for:

% is-at-least 5.9.0.3  5.9  && echo yes || echo no
yes   # should be no

This can be easily fixed by adding one more '0' to
line34 of current is-at-least: version=(${=2} 0)

[2] But there is another problem:

% is-at-least 2  1a  && echo yes || echo no
no
% is-at-least 2  a.1a  && echo yes || echo no
yes

Since segment with no digits ('a' in a.1a) is ignored,
both should give 'no'. It would be possible to fix this
by using min_cnt (or ++min_cnt) for min_ver in

line41:      order=( ${version[ver_cnt]} ${min_ver[ver_cnt]} )

But using two counters in nested two while loops is too complicated
for me, ...

[3] so I would like to simplify is-at-least as in the (tentative)
patch below.

There are two differences from the current version if segments contain
non-digit characters:
   
  For segments of the from 'foo123' (a text followed by a number),
  current version removes 'foo' and treat it as '123' (to be compatible
  with very old version string of zsh?), but my (tentative) version
  treat it as is. 'git log -p Config/version.mk' does not show any such
  'old' version string. Do we still need to support it?

  For segments like 'a2b' current version uses 'lexical' sort for
  comparison, but my version always uses 'numerical'sort.
  This means that 'a2b' is newer than 'a12b' in the current version,
  but older in mine. Why we need to use 'lexical' ordering here?

If there is a concern that these change would break existing code,
I can modify my patch by adding a few more lines.


diff --git a/Functions/Misc/is-at-least b/Functions/Misc/is-at-least
index 5985684be..f81593920 100644
--- a/Functions/Misc/is-at-least
+++ b/Functions/Misc/is-at-least
@@ -1,62 +1,49 @@
 #
-# Test whether $ZSH_VERSION (or some value of your choice, if a second argument
-# is provided) is greater than or equal to x.y.z-r (in argument one). In fact,
-# it'll accept any dot/dash-separated string of numbers as its second argument
-# and compare it to the dot/dash-separated first argument. Leading non-number
-# parts of a segment (such as the "zefram" in 3.1.2-zefram4) are not considered
-# when the comparison is done; only the numbers matter. Any left-out segments
-# in the first argument that are present in the version string compared are
-# considered as zeroes, eg 3 == 3.0 == 3.0.0 == 3.0.0.0 and so on.
+# is-at-least: compare two version strings
 #
-# Usage examples:
-# is-at-least 3.1.6-15 && setopt NO_GLOBAL_RCS
-# is-at-least 3.1.0 && setopt HIST_REDUCE_BLANKS
-# is-at-least 586 $MACHTYPE && echo 'You could be running Mandrake!'
-# is-at-least $ZSH_VERSION || print 'Something fishy here.'
+# Usage:  is-at-least minimum_version [current_version]
+# 
+# Returns true if current_version is equal to or newer than minimum_version.
+# If current_version is omitted, $ZSH_VERSION is used.
+# {minimum,current}_version is a string consisting of a few 'segments'
+# joined by either '.' or '-'. For example:
+#     1.2-test          3.1.2-zefram4
+#     4.4.5beta23       12.34-patch23a
+#
+# A segment with no digits, such as 'test' above, is ignored.
+# If number of segments in the two version strings differ, missing
+# segments are assumed to be '0'. This means
+#     5.9, 5.9.0, 5.9.0.0, 5.9-test
+# are all considered to be the same version.
 #
-# Note that segments that contain no digits at all are ignored, and leading
-# text is discarded if trailing digits follow, because this was the meaning
-# of certain zsh version strings in the early 2000s.  Other segments that
-# begin with digits are compared using NUMERIC_GLOB_SORT semantics, and any
-# other segments starting with text are compared lexically.
-
 emulate -L zsh
+setopt extended_glob
 
-local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version order
+local IFS=".-" min_ver cur_ver n
 
 : ${2=$ZSH_VERSION}
 
 # sort out the easy corner cases first
-[[ $1 = $2 ]] && return 0 # same version
-[[ -n $2 ]] || return 1   # no version
+[[ -z $1 || -z $2 ]] && return 1    # no version
+[[ $1 = $2 ]] && return 0           # same version
 
+# split into segments
 min_ver=(${=1})
-version=(${=2} 0)
-
-while (( $min_cnt <= ${#min_ver} )); do
-  while [[ "$part" != <-> ]]; do
-    (( ++ver_cnt > ${#version} )) && return 0
-    if [[ ${version[ver_cnt]} = *[0-9][^0-9]* ]]; then
-      # Contains a number followed by text.  Not a zsh version string.
-      order=( ${version[ver_cnt]} ${min_ver[ver_cnt]} )
-      if [[ ${version[ver_cnt]} = <->* ]]; then
-        # Leading digits, compare by sorting with numeric order.
-        [[ $order != ${${(On)order}} ]] && return 1
-      else
-        # No leading digits, compare by sorting in lexical order.
-        [[ $order != ${${(O)order}} ]] && return 1
-      fi
-      [[ $order[1] != $order[2] ]] && return 0
-    fi
-    part=${version[ver_cnt]##*[^0-9]}
-  done
-
-  while true; do
-    (( ++min_cnt > ${#min_ver} )) && return 0
-    [[ ${min_ver[min_cnt]} = <-> ]] && break
-  done
-
-  (( part > min_ver[min_cnt] )) && return 0
-  (( part < min_ver[min_cnt] )) && return 1
-  part=''
+cur_ver=(${=2})
+
+# remove segmets containing no digits
+min_ver=( ${min_ver:#[^0-9]##} )
+cur_ver=( ${cur_ver:#[^0-9]##} )
+(( $#min_ver == 0 || $#cur_ver == 0 )) && return 1
+
+# find the first segment that differs
+for (( n = 1; n <= $#min_ver; ++n )) do
+  [[ ${min_ver[n]} != ${cur_ver[n]-0} ]] && break
 done
+
+# if all segments in $min_ver are equal to those in $cur_ver
+(( n > $#min_ver )) && return 0
+
+# now compare the two segments that differ
+order=( ${cur_ver[n]-0} ${min_ver[n]-0} )
+[[ $order != ${${(On)order}} ]] && return 1 || return 0







Messages sorted by: Reverse Date, Date, Thread, Author