# Copyright 1999-2021 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # @AUTHOR: # Ulrich Müller # Michał Górny # It is a cut-down and modified version of the now-gone eapi7-ver.eclass. if [[ -z ${__GENTOO_VER_SH_INCLUDED__:-} ]]; then __GENTOO_VER_SH_INCLUDED__=x source "$(dirname "${BASH_SOURCE[0]}")/util.sh" VER_ERE="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$" # @FUNCTION: _ver_compare_int # @USAGE: # @RETURN: 0 if -eq , 1 if -lt , 3 if -gt # @INTERNAL # @DESCRIPTION: # Compare two non-negative integers and , of arbitrary length. # If is equal to, less than, or greater than , return 0, 1, or 3 # as exit status, respectively. _ver_compare_int() { local a=$1 b=$2 d=$(( ${#1}-${#2} )) # Zero-pad to equal length if necessary. if [[ ${d} -gt 0 ]]; then printf -v b "%0${d}d%s" 0 "${b}" elif [[ ${d} -lt 0 ]]; then printf -v a "%0$(( -d ))d%s" 0 "${a}" fi [[ ${a} > ${b} ]] && return 3 [[ ${a} == "${b}" ]] } # @FUNCTION: _ver_compare # @USAGE: # @RETURN: 1 if < , 2 if = , 3 if > # @INTERNAL # @DESCRIPTION: # Compare two versions and . If is less than, equal to, # or greater than , return 1, 2, or 3 as exit status, respectively. _ver_compare() { local va=${1} vb=${2} a an al as ar b bn bl bs br re LC_ALL=C re=${VER_ERE} [[ ${va} =~ ${re} ]] || fail "${FUNCNAME[0]}: invalid version: ${va}" an=${BASH_REMATCH[1]} al=${BASH_REMATCH[3]} as=${BASH_REMATCH[4]} ar=${BASH_REMATCH[7]} [[ ${vb} =~ ${re} ]] || fail "${FUNCNAME[0]}: invalid version: ${vb}" bn=${BASH_REMATCH[1]} bl=${BASH_REMATCH[3]} bs=${BASH_REMATCH[4]} br=${BASH_REMATCH[7]} # Compare numeric components (PMS algorithm 3.2) # First component _ver_compare_int "${an%%.*}" "${bn%%.*}" || return while [[ ${an} == *.* && ${bn} == *.* ]]; do # Other components (PMS algorithm 3.3) an=${an#*.} bn=${bn#*.} a=${an%%.*} b=${bn%%.*} if [[ ${a} == 0* || ${b} == 0* ]]; then # Remove any trailing zeros [[ ${a} =~ 0+$ ]] && a=${a%"${BASH_REMATCH[0]}"} [[ ${b} =~ 0+$ ]] && b=${b%"${BASH_REMATCH[0]}"} [[ ${a} > ${b} ]] && return 3 [[ ${a} < ${b} ]] && return 1 else _ver_compare_int "${a}" "${b}" || return fi done [[ ${an} == *.* ]] && return 3 [[ ${bn} == *.* ]] && return 1 # Compare letter components (PMS algorithm 3.4) [[ ${al} > ${bl} ]] && return 3 [[ ${al} < ${bl} ]] && return 1 # Compare suffixes (PMS algorithm 3.5) as=${as#_}${as:+_} bs=${bs#_}${bs:+_} while [[ -n ${as} && -n ${bs} ]]; do # Compare each suffix (PMS algorithm 3.6) a=${as%%_*} b=${bs%%_*} if [[ ${a%%[0-9]*} == "${b%%[0-9]*}" ]]; then _ver_compare_int "${a##*[a-z]}" "${b##*[a-z]}" || return else # Check for p first [[ ${a%%[0-9]*} == p ]] && return 3 [[ ${b%%[0-9]*} == p ]] && return 1 # Hack: Use that alpha < beta < pre < rc alphabetically [[ ${a} > ${b} ]] && return 3 || return 1 fi as=${as#*_} bs=${bs#*_} done if [[ -n ${as} ]]; then [[ ${as} == p[_0-9]* ]] && return 3 || return 1 elif [[ -n ${bs} ]]; then [[ ${bs} == p[_0-9]* ]] && return 1 || return 3 fi # Compare revision components (PMS algorithm 3.7) _ver_compare_int "${ar#-r}" "${br#-r}" || return return 2 } # @FUNCTION: ver_test # @USAGE: [] # @DESCRIPTION: # Check if the relation is true. If is not specified, # default to ${PVR}. can be -gt, -ge, -eq, -ne, -le, -lt. # Both versions must conform to the PMS version syntax (with optional # revision parts), and the comparison is performed according to # the algorithm specified in the PMS. ver_test() { local va op vb if [[ $# -eq 3 ]]; then va=${1} shift else va=${PVR} fi [[ $# -eq 2 ]] || fail "${FUNCNAME[0]}: bad number of arguments" op=${1} vb=${2} case ${op} in -eq|-ne|-lt|-le|-gt|-ge) ;; *) fail "${FUNCNAME[0]}: invalid operator: ${op}" ;; esac _ver_compare "${va}" "${vb}" test $? "${op}" 2 } # symbolic names for use with gentoo_ver_cmp_out GV_LT=1 GV_EQ=2 GV_GT=3 # Compare two versions. The result can be compared against GV_LT, GV_EQ and GV_GT variables. # # Params: # # 1 - version 1 # 2 - version 2 # 3 - name of variable to store the result in function gentoo_ver_cmp_out() { local v1 v2 v1=${1}; shift v2=${1}; shift local -n out_ref=${1}; shift out_ref=0 _ver_compare "${v1}" "${v2}" || out_ref=${?} case ${out_ref} in "${GV_LT}"|"${GV_EQ}"|"${GV_GT}") return 0 ;; *) fail "unexpected return value ${out_ref} from _ver_compare for ${v1} and ${v2}" ;; esac } fi