Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [PATCH] fix/simplify is-at-least
I've almost forgotten what I was trying to achieve, but I feel
the simpler the better.
I will push the following (almost the same as the 1st version),
but feel free to modify it as far as it doesn't conflict with the
zsh's version strings.
diff --git a/Functions/Misc/is-at-least b/Functions/Misc/is-at-least
index 5985684be..954990dcf 100644
--- a/Functions/Misc/is-at-least
+++ b/Functions/Misc/is-at-least
@@ -1,62 +1,53 @@
#
-# 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.
+#
+# Two segments are compared numerically if the first differing characters
+# are both digits, and lexically otherwise.
+#
+# 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 order
: ${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 segments 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
diff --git a/Test/Z01is-at-least.ztst b/Test/Z01is-at-least.ztst
index 039b3e737..57fb92696 100644
--- a/Test/Z01is-at-least.ztst
+++ b/Test/Z01is-at-least.ztst
@@ -16,12 +16,27 @@
done
0:is-at-least smoke test
- is-at-least 5.8.0.2 5.8
-1f:regression test: Two trailing zeroes are filled in
-# TODO: When fixing this, extend the smoke test to cover this.
+# versions in v1 should be equal
+# versions in v2 should be newer than those in v1
+ v1=( 1 1.0 1.0.0 1.0.0.0 1-b 1.X-0 )
+ v2=( 1.0.0.1 1.0.1 1.0.1.0 1.0.1.1 1-a-0-1 1-0-a.1)
+ for (( i = 1; i < $#v1; ++i )); do
+ for (( j = 1; j < $#v1; ++j )); do
+ is-at-least $v1[i] $v1[j] || echo "$v1[i] ≰ $v1[j]"
+ done
+ done
+ for (( i = 1; i < $#v1; ++i )); do
+ for (( j = 1; j < $#v2; ++j )); do
+ is-at-least $v1[i] $v2[j] || echo "$v1[i] ≰ $v2[j]"
+ { ! is-at-least $v2[j] $v1[i] } || echo "$v2[j] ≤ $v1[i]"
+ done
+ done
+0:trailing zeroes are filled in, text-only segments are ignored
- is-at-least 5.8.0.2 5.8.0.0
-1:regression test: Two trailing zeroes are filled in
-# TODO: Extend the smoke test to cover this.
+ local min cur
+ for min cur in 1.2 1.12 1.2b 1.12a 1-a3 1-b1; do
+ is-at-least $min $cur || echo "$min ≰ $cur"
+ done
+0:numerical or lexical order
%clean
Messages sorted by:
Reverse Date,
Date,
Thread,
Author