#!/bin/bash

# This program will take two EPOCH-VERSION-RELEASE strings and compare 
# them.  The purpose is to be able to figure out if one package is newer 
# then another without using the command line version of RPM.
#
# Based on the algorithm described in rpm version 4.1 lib/psm.c and 
# lib/rpmvercmp.c
#
# rpmvercmp (version 1)
#
# Written by
# Mark Hatle (fray@mvista.com)
#
# Copyright 2004 MontaVista Software, Inc.
# 
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License   
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#
# This is a shell implementation of the logic from the lib/rpmvercmp.c
# rpmvercmp(const char * a, const char * b) from rpm
#
# input: $1 = a
#        $2 = b
#
# output:
#        0 - a newer then b
#        1 - b is newer then a
#        2 - a and b are the same version
rpmvercmp()
{
  local versionA="$1"
  local versionB="$2"

  local local_verA=""
  local local_verB=""

  # The idea is to compare chunks..
  # We first split at the first non-alphanumeric (partVer / Remainder)
  #  Take the partVer and then figure out what the first character type is
  #    split the result based on the character type
  #    place the stuff after the split back in front of the Remainder
  #    compare (numerically, or alphabetically) the "result"
  #  repeat until there is nothing left to verify..

  # First check to make sure they're not equal!
  if [ "$versionA" = "$versionB" ]; then
    return 2
  fi

  while [ -n "$versionA" -a -n "$versionB" ]; do
    local_verA="`echo $versionA | sed -e 's/^[^a-zA-Z0-9]//' -e 's/\([^a-zA-Z0-9]\)/ \1/'`"
    local_verB="`echo $versionB | sed -e 's/^[^a-zA-Z0-9]//' -e 's/\([^a-zA-Z0-9]\)/ \1/'`"

    versionA="`echo "$local_verA " | cut -d ' ' -f 2`"
    local_verA="`echo "$local_verA" | cut -d ' ' -f 1`"

    versionB="`echo "$local_verB " | cut -d ' ' -f 2`"
    local_verB="`echo "$local_verB" | cut -d ' ' -f 1`"

    # isNum = 0 if it's a number
    # isNum != 0 if it's not
    echo $local_verA | cut -c 1 | grep -q [0-9]
    isNum=$?

    if [ $isNum -eq 0 ]; then
      local_verA="`echo $local_verA | sed 's/\([^0-9]\)/ \1/'`"
      local_verB="`echo $local_verB | sed 's/\([^0-9]\)/ \1/'`"
    else
      local_verA="`echo $local_verA | sed 's/\([^A-Za-z]\)/ \1/'`"
      local_verB="`echo $local_verB | sed 's/\([^A-Za-z]\)/ \1/'`"
    fi

    versionA="`echo "$local_verA " | cut -d ' ' -f 2`"${versionA}
    local_verA="`echo "$local_verA" | cut -d ' ' -f 1`"

    versionB="`echo "$local_verB " | cut -d ' ' -f 2`"${versionB}
    local_verB="`echo "$local_verB" | cut -d ' ' -f 1`"

#    echo "compare '$local_verA' to '$local_verB'"

    # Different types action is specified in the lib/rpmvercmp.c
    if [ -z "$local_verA" -o -z "$local_verB" ]; then
#      echo "Different Types!"
      return 1
    fi
    
    if [ $isNum -eq 0 ]; then
      if [ "$local_verA" -gt "$local_verB" ]; then return 0 ; fi
      if [ "$local_verA" -lt "$local_verB" ]; then return 1 ; fi
    else
      if [ "$local_verA" \> "$local_verB" ]; then return 0 ; fi
      if [ "$local_verA" \< "$local_verB" ]; then return 1 ; fi
    fi
  done

  # Check if anything is left over, they win
  if [ -n "$versionA" ]; then
    return 0
  fi
  if [ -n "$versionB" ]; then
    return 1
  fi

  # They were equal.. we only get here if the seperators were different!
  return 2
}

# Input
#  $1 = "EPOCH-VERSION-RELEASE"
#  $2 = "EPOCH-VERSION-RELEASE"
#
# Input is expected to have been validated!
#
# EPOCH may be blank or set to "(none)"
#
# Result
#  0 $1 is newer then or same version as $2
#  1 $2 is a newer version then $1

rpmVersionCompare() {
  local A="$1"
  local B="$2"

  # Get this out of the way...
  if [ "$A" = "$B" ]; then
    return 0
  fi

  # First compare the epoch
  local epochA="$( echo $A | cut -f 1 -d - )"
  local epochB="$( echo $B | cut -f 1 -d - )"
  if [ "$epochA" = "(none)" ]; then epochA="" ; fi
  if [ "$epochB" = "(none)" ]; then epochB="" ; fi

  if [ -n "$epochA" -a -z "$epochB" ]; then return 0 ; fi
  if [ -z "$epochA" -a -n "$epochB" ]; then return 1 ; fi
  if [ -n "$epochA" -a -n "$epochB" ]; then
    if [ "$epochA" -gt "$epochB" ]; then 
      return 0
    fi
    if [ "$epochA" -lt "$epochB" ]; then 
      return 1
    fi
  fi

  local versionA="$( echo $A | cut -f 2 -d - )"
  local versionB="$( echo $B | cut -f 2 -d - )"

  rpmvercmp "$versionA" "$versionB"
  ret=$?
  if [ $ret -ne 2 ]; then
    return $ret
  fi

  local releaseA="$( echo $A | cut -f 3 -d - )"
  local releaseB="$( echo $B | cut -f 3 -d - )"

  rpmvercmp "$releaseA" "$releaseB"
  ret=$?
  if [ $ret -ne 2 ]; then
    return $ret
  fi

  return 0
}

rpmVersionCompare "$1" "$2"

if [ $? -eq 0 ] ; then
  echo "res: (A) $1 is newer then or equal to (B) $2"
else
  echo "res: (B) $2 is newer then (A) $1"
fi
