#!/bin/bash # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 __eapi7_ver_parse_range() { local range=${1} local max=${2} [[ ${range} == [0-9]* ]] \ || die "${FUNCNAME}: range must start with a number" start=${range%-*} [[ ${range} == *-* ]] && end=${range#*-} || end=${start} if [[ ${end} ]]; then [[ ${start} -le ${end} ]] \ || die "${FUNCNAME}: end of range must be >= start" [[ ${end} -le ${max} ]] || end=${max} else end=${max} fi } __eapi7_ver_split() { local v=${1} LC_ALL=C comp=() # get separators and components local s c while [[ ${v} ]]; do # cut the separator s=${v%%[a-zA-Z0-9]*} v=${v:${#s}} # cut the next component; it can be either digits or letters [[ ${v} == [0-9]* ]] && c=${v%%[^0-9]*} || c=${v%%[^a-zA-Z]*} v=${v:${#c}} comp+=( "${s}" "${c}" ) done } ver_cut() { local range=${1} local v=${2:-${PV}} local start end local -a comp __eapi7_ver_split "${v}" local max=$((${#comp[@]}/2)) __eapi7_ver_parse_range "${range}" "${max}" local IFS= if [[ ${start} -gt 0 ]]; then start=$(( start*2 - 1 )) fi echo "${comp[*]:start:end*2-start}" } ver_rs() { local v (( ${#} & 1 )) && v=${@: -1} || v=${PV} local start end i local -a comp __eapi7_ver_split "${v}" local max=$((${#comp[@]}/2 - 1)) while [[ ${#} -ge 2 ]]; do __eapi7_ver_parse_range "${1}" "${max}" for (( i = start*2; i <= end*2; i+=2 )); do [[ ${i} -eq 0 && -z ${comp[i]} ]] && continue comp[i]=${2} done shift 2 done local IFS= echo "${comp[*]}" } __eapi7_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}" ]] } __eapi7_ver_compare() { local va=${1} vb=${2} a an al as ar b bn bl bs br re LC_ALL=C re="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$" [[ ${va} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${va}" an=${BASH_REMATCH[1]} al=${BASH_REMATCH[3]} as=${BASH_REMATCH[4]} ar=${BASH_REMATCH[7]} [[ ${vb} =~ ${re} ]] || die "${FUNCNAME}: 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 __eapi7_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 __eapi7_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 __eapi7_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) __eapi7_ver_compare_int "${ar#-r}" "${br#-r}" || return return 2 } ver_test() { local va op vb if [[ $# -eq 3 ]]; then va=${1} shift else va=${PVR} fi [[ $# -eq 2 ]] || die "${FUNCNAME}: bad number of arguments" op=${1} vb=${2} case ${op} in -eq|-ne|-lt|-le|-gt|-ge) ;; *) die "${FUNCNAME}: invalid operator: ${op}" ;; esac __eapi7_ver_compare "${va}" "${vb}" test $? "${op}" 2 }