Comparing full versions numbers (xx.xx.xx.xx ? xx.xx.xx.xx)

From NSIS Wiki
Jump to navigationJump to search
Author: anonymous (talk, contrib)


Description

This script compares two versions: lets name them needed and existing, and check if existing version greater than or equal to needed one.

Version is a string in format 'xx.xx.xx' where xx is integer numbers.

Number of sections (major version, minor version, etc.) in versions can differs in existing and needed versions.

Empty version means lowest version.


So it is possible to compare:

;needed  | existing           -> result
;'5.1'         | '6.0.2800.106'  -> 1
;'6.0'         | '6.0.2800.106'  -> 1
;'2.5'         | ''                       -> 0
;'7.2.5'      | '6.0'                  -> 0
;'7.2.5'      | '8.0'                  -> 1
;'5.1'         | '5.1'                  -> 1   :)
;'2.8'         | '2.50.4403.9'    -> 1 (!!!)
;'2.80'       | '2.50.4403.9'    -> 0 (!!!)

Example

 Your program need IE version 5.1 or higher
 and on user machine installed '6.0.2800.1106'

So you should call this:

   Push "5.1" ;Needed verion of product
   Push  $R0   ;Here you have to put existing version of product on target
                        ;computer
   Call CompareVersions
   Pop $R0   ; If $R0 = '1' then existing version greater than or 
                     ;equval to a needed version

In our case we will have '1' in $R0, witch means "everithing is OK" :)

Note Added 9.06.2004

Dont forget, what versions compared as integer numbers!

Example from real life:

Checking MDAC version. (problem that in MDAC versions minor version is two digit number, some peoples (including me:) sometimes forget this)

So, you need MDAC v2.8

On system installed MDAC v2.50.4403.9

If you call

   Push "2.8"
   Push  "2.50.4403.9"
   Call CompareVersions
   Pop $R0

in $R0 will be 1 !!!! What's because 2.8 less then 2.50 (2 = 2 and 8 less than 50)

Solution is to check MDAC v2.80

   Push "2.80"
   Push  "2.50.4403.9"
   Call CompareVersions
   Pop $R0

in $R0 will be 0, thats just what we need :)

The Script

;-----------------------------------------------------------------------------
 ; CompareVersions
 ; input:
 ;    top of stack = existing version
 ;    top of stack-1 = needed version
 ; output:
 ;    top of stack = 1 if current version => neded version, else 0
 ; version is a string in format "xx.xx.xx.xx" (number of interger sections 
 ; can be different in needed and existing versions)
 
Function CompareVersions
   ; stack: existing ver | needed ver
   Exch $R0 
   Exch
   Exch $R1 
   ; stack: $R1|$R0
 
   Push $R1
   Push $R0
   ; stack: e|n|$R1|$R0
 
   ClearErrors
   loop:
      IfErrors VersionNotFound
      Strcmp $R0 "" VersionTestEnd
 
      Call ParseVersion
      Pop $R0
      Exch
 
      Call ParseVersion
      Pop $R1 
      Exch
 
      IntCmp $R1 $R0 +1 VersionOk VersionNotFound
      Pop $R0
      Push $R0
 
   goto loop
 
   VersionTestEnd:
      Pop $R0
      Pop $R1
      Push $R1
      Push $R0
      StrCmp $R0 $R1 VersionOk VersionNotFound
 
   VersionNotFound:
      StrCpy $R0 "0"
      Goto end
 
   VersionOk:
      StrCpy $R0 "1"
end:
   ; stack: e|n|$R1|$R0
   Exch $R0
   Pop $R0
   Exch $R0
   ; stack: res|$R1|$R0
   Exch
   ; stack: $R1|res|$R0
   Pop $R1
   ; stack: res|$R0
   Exch
   Pop $R0
   ; stack: res
FunctionEnd
 
;---------------------------------------------------------------------------------------
 ; ParseVersion
 ; input:
 ;      top of stack = version string ("xx.xx.xx.xx")
 ; output: 
 ;      top of stack   = first number in version ("xx")
 ;      top of stack-1 = rest of the version string ("xx.xx.xx")
Function ParseVersion
   Exch $R1 ; version
   Push $R2
   Push $R3
 
   StrCpy $R2 1
   loop:
      StrCpy $R3 $R1 1 $R2
      StrCmp $R3 "." loopend
      StrLen $R3 $R1
      IntCmp $R3 $R2 loopend loopend
      IntOp $R2 $R2 + 1
      Goto loop
   loopend:
   Push $R1
   StrCpy $R1 $R1 $R2
   Exch $R1
 
   StrLen $R3 $R1
   IntOp $R3 $R3 - $R2
   IntOp $R2 $R2 + 1
   StrCpy $R1 $R1 $R3 $R2
 
   Push $R1
 
   Exch 2
   Pop $R3
 
   Exch 2
   Pop $R2
 
   Exch 2
   Pop $R1
FunctionEnd
;---------------------------------------------------------------------------------------

If someone has any questions about code write here: woodman@e-pochta.kiev.ua. P.S. Sorry for poor english (my native language is russian). Where are not much comments left in scrip after publishing because of that :)